lolcommits 0.13.1 → 0.14.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 (43) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop.yml +1 -0
  3. data/.rubocop_todo.yml +3 -3
  4. data/CHANGELOG.md +18 -7
  5. data/Gemfile +2 -0
  6. data/README.md +101 -76
  7. data/Rakefile +3 -1
  8. data/bin/console +1 -0
  9. data/bin/lolcommits +37 -32
  10. data/config/cucumber.yml +1 -1
  11. data/features/bugs.feature +2 -2
  12. data/features/lolcommits.feature +42 -17
  13. data/features/step_definitions/lolcommits_steps.rb +7 -3
  14. data/lib/lolcommits/animated_gif.rb +77 -0
  15. data/lib/lolcommits/backends/git_info.rb +15 -11
  16. data/lib/lolcommits/backends/installation_git.rb +4 -3
  17. data/lib/lolcommits/backends/installation_mercurial.rb +1 -1
  18. data/lib/lolcommits/backends/mercurial_info.rb +13 -9
  19. data/lib/lolcommits/capturer.rb +14 -6
  20. data/lib/lolcommits/capturer/capture_cygwin.rb +3 -14
  21. data/lib/lolcommits/capturer/capture_fake.rb +8 -2
  22. data/lib/lolcommits/capturer/capture_linux.rb +11 -10
  23. data/lib/lolcommits/capturer/capture_linux_video.rb +15 -0
  24. data/lib/lolcommits/capturer/capture_mac.rb +6 -11
  25. data/lib/lolcommits/capturer/capture_mac_video.rb +23 -0
  26. data/lib/lolcommits/capturer/capture_windows.rb +14 -9
  27. data/lib/lolcommits/capturer/capture_windows_video.rb +46 -0
  28. data/lib/lolcommits/cli/fatals.rb +1 -1
  29. data/lib/lolcommits/cli/launcher.rb +1 -1
  30. data/lib/lolcommits/cli/timelapse_gif.rb +28 -12
  31. data/lib/lolcommits/configuration.rb +4 -26
  32. data/lib/lolcommits/platform.rb +4 -4
  33. data/lib/lolcommits/plugin/base.rb +2 -2
  34. data/lib/lolcommits/plugin/configuration_helper.rb +1 -1
  35. data/lib/lolcommits/runner.rb +138 -69
  36. data/lib/lolcommits/version.rb +2 -2
  37. data/lolcommits.gemspec +4 -2
  38. data/test/assets/test_image.jpg +0 -0
  39. data/test/assets/test_video.mp4 +0 -0
  40. metadata +12 -9
  41. data/lib/lolcommits/capturer/capture_linux_animated.rb +0 -74
  42. data/lib/lolcommits/capturer/capture_mac_animated.rb +0 -75
  43. data/lib/lolcommits/capturer/capture_windows_animated.rb +0 -110
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lolcommits
4
+ class CaptureLinuxVideo < Capturer
5
+ def capture
6
+ system_call "ffmpeg -nostats -v quiet -y -f video4linux2 -video_size 640x480 -i #{capture_device_string} -t #{capture_duration} \"#{capture_path}\" > /dev/null"
7
+ end
8
+
9
+ private
10
+
11
+ def capture_device_string
12
+ capture_device || Dir.glob('/dev/video*').first
13
+ end
14
+ end
15
+ end
@@ -2,19 +2,14 @@
2
2
 
3
3
  module Lolcommits
4
4
  class CaptureMac < Capturer
5
- def capture_device_string
6
- @capture_device.nil? ? nil : "-d \"#{@capture_device}\""
5
+ def capture
6
+ system_call "#{executable_path} -q \"#{capture_path}\" -w #{capture_delay} #{capture_device_string}"
7
7
  end
8
8
 
9
- def capture
10
- # TODO: check we have a webcam we can capture from first. See issue #219
11
- # operating laptop in clamshell (lid closed) from 2nd desktop screen,
12
- # needs to better handle the capturer (imagesnap, videosnap
13
- # CommandCam, mplayer) return code or check with an option before
14
- # attempting capture. Alt solution is puttin in prompt mode option :(
15
- call_str = "#{executable_path} -q \"#{snapshot_location}\" -w #{capture_delay} #{capture_device_string}"
16
- debug "Capturer: making system call for #{call_str}"
17
- system(call_str)
9
+ private
10
+
11
+ def capture_device_string
12
+ capture_device.nil? ? '' : "-d \"#{capture_device}\""
18
13
  end
19
14
 
20
15
  def executable_path
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lolcommits
4
+ class CaptureMacVideo < Capturer
5
+ def capture
6
+ system_call "#{executable_path} -p 640x480 #{capture_device_string}#{capture_delay_string}-t #{capture_duration} --no-audio \"#{capture_path}\" > /dev/null"
7
+ end
8
+
9
+ private
10
+
11
+ def capture_device_string
12
+ "-d \"#{capture_device}\" " if capture_device
13
+ end
14
+
15
+ def capture_delay_string
16
+ "-w \"#{capture_delay}\" " if capture_delay.positive?
17
+ end
18
+
19
+ def executable_path
20
+ File.join(Configuration::LOLCOMMITS_ROOT, 'vendor', 'ext', 'videosnap', 'videosnap')
21
+ end
22
+ end
23
+ end
@@ -3,19 +3,24 @@
3
3
  module Lolcommits
4
4
  class CaptureWindows < Capturer
5
5
  def capture
6
- # DirectShow takes a while to show... at least for me anyway
7
- delaycmd = ' /delay 3000'
8
- if capture_delay > 0
9
- # CommandCam delay is in milliseconds
10
- delaycmd = " /delay #{capture_delay * 1000}"
11
- end
12
-
13
- _stdin, stdout, _stderr = Open3.popen3("#{executable_path} /filename #{snapshot_location}#{delaycmd}")
6
+ _stdin, stdout, _stderr = Open3.popen3("#{executable_path} /filename #{capture_path}#{delay_arg}")
14
7
 
15
- # looks like we still need to read the output for something to happen
8
+ # need to read the output for something to happen
16
9
  stdout.read
17
10
  end
18
11
 
12
+ private
13
+
14
+ def delay_arg
15
+ # CommandCam delay is in milliseconds
16
+ if capture_delay.positive?
17
+ " /delay #{capture_delay * 1000}"
18
+ else
19
+ # DirectShow takes a while to show, default to 3 sec delay
20
+ ' /delay 3000'
21
+ end
22
+ end
23
+
19
24
  def executable_path
20
25
  File.join(Configuration::LOLCOMMITS_ROOT, 'vendor', 'ext', 'CommandCam', 'CommandCam.exe')
21
26
  end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lolcommits
4
+ class CaptureWindowsVideo < Capturer
5
+ def capture
6
+ return unless capture_device_string
7
+
8
+ system_call "ffmpeg -v quiet -y -f dshow -i video=\"#{capture_device_string}\" -video_size 640x480 -t #{capture_duration} \"#{capture_path}\" > NUL"
9
+ end
10
+
11
+ private
12
+
13
+ def capture_device_string
14
+ capture_device || device_names.first
15
+ end
16
+
17
+ def ffpmeg_list_devices_cmd
18
+ 'ffmpeg -list_devices true -f dshow -i dummy 2>&1'
19
+ end
20
+
21
+ # inspired by this code from @rdp http://tinyurl.com/y7t276bh
22
+ def device_names
23
+ @device_names ||= begin
24
+ names = []
25
+ cmd_output = ''
26
+ count = 0
27
+ while cmd_output.empty? || !cmd_output.split('DirectShow')[2]
28
+ cmd_output = system_call(ffpmeg_list_devices_cmd, true)
29
+ count += 1
30
+ raise 'failed to find a video capture device with ffmpeg -list_devices' if count == 5
31
+
32
+ sleep 0.1
33
+ end
34
+ cmd_output.gsub!("\r\n", "\n")
35
+ video = cmd_output.split('DirectShow')[1]
36
+
37
+ video.lines.map do |line|
38
+ names << Regexp.last_match(1) if line =~ /"(.+)"\n/
39
+ end
40
+
41
+ debug "found #{names.length} video devices: #{names.join(', ')}"
42
+ names
43
+ end
44
+ end
45
+ end
46
+ end
@@ -59,7 +59,7 @@ module Lolcommits
59
59
  # If we are not in a git repo, we can't do git related things!
60
60
  # Die with an informative error message in that case.
61
61
  def self.die_if_not_vcs_repo!
62
- debug 'Checking for valid vcs repo'
62
+ debug 'Checking for valid VCS repo'
63
63
  current = File.expand_path('.')
64
64
  parent = File.dirname(current)
65
65
  while current != parent
@@ -10,7 +10,7 @@ module Lolcommits
10
10
  # Right now this is mostly just a wrapper for Launchy, in case we want
11
11
  # to factor out it's dependency later or swap it out.
12
12
  class Launcher
13
- def self.open_image(path)
13
+ def self.open_file(path)
14
14
  open_with_launchy(path)
15
15
  end
16
16
 
@@ -7,9 +7,9 @@ module Lolcommits
7
7
  module CLI
8
8
  # Creates an animated timeline GIF of lolcommits history.
9
9
  class TimelapseGif
10
- # param config [Lolcommits::Configuration]
11
- def initialize(config)
12
- @configuration = config
10
+ # param loldir [String] path to loldir
11
+ def initialize(loldir)
12
+ self.loldir = loldir
13
13
  end
14
14
 
15
15
  # Runs the history timeline animator task thingy
@@ -17,11 +17,11 @@ module Lolcommits
17
17
  def run(args = nil)
18
18
  case args
19
19
  when 'today'
20
- lolimages = @configuration.jpg_images_today
21
- filename = "#{Date.today}.gif"
20
+ lolimages = jpg_images_today
21
+ filename = Date.today.to_s
22
22
  else
23
- lolimages = @configuration.jpg_images
24
- filename = 'archive.gif'
23
+ lolimages = jpg_images
24
+ filename = "all-until-#{Time.now.strftime('%d-%b-%Y--%Hh%Mm%Ss')}"
25
25
  end
26
26
 
27
27
  if lolimages.empty?
@@ -29,14 +29,30 @@ module Lolcommits
29
29
  exit 1
30
30
  end
31
31
 
32
- puts '*** Generating animated gif.'
32
+ puts '*** Generating animated timelapse gif.'
33
33
 
34
- gif = MiniMagick::Image.new File.join @configuration.archivedir, filename
34
+ gif = MiniMagick::Image.new(File.join(timelapses_dir_path, "#{filename}.gif"))
35
+ gif.run_command('convert', *['-delay', '50', '-loop', '0', lolimages, gif.path].flatten)
35
36
 
36
- # This is for ruby 1.8.7, *lolimages just doesn't work with ruby 187
37
- gif.run_command('convert', *['-delay', '50', '-loop', '0', lolimages, gif.path.to_s].flatten)
37
+ puts "*** Done, generated at #{gif.path}"
38
+ end
39
+
40
+ private
41
+
42
+ attr_accessor :loldir
43
+
44
+ def jpg_images
45
+ Dir.glob(File.join(loldir, '*.jpg')).sort_by { |f| File.mtime(f) }
46
+ end
47
+
48
+ def jpg_images_today
49
+ jpg_images.select { |f| Date.parse(File.mtime(f).to_s) == Date.today }
50
+ end
38
51
 
39
- puts "*** #{gif.path} generated."
52
+ def timelapses_dir_path
53
+ dir = File.join(loldir, 'timelapses')
54
+ FileUtils.mkdir_p(dir)
55
+ dir
40
56
  end
41
57
  end
42
58
  end
@@ -38,34 +38,12 @@ module Lolcommits
38
38
  @loldir = Configuration.loldir_for(basename)
39
39
  end
40
40
 
41
- def archivedir
42
- dir = File.join(loldir, 'archive')
43
- FileUtils.mkdir_p dir unless File.directory? dir
44
- dir
41
+ def sha_path(sha, ext)
42
+ File.join loldir, "#{sha}.#{ext}"
45
43
  end
46
44
 
47
- def jpg_images
48
- Dir.glob(File.join(loldir, '*.jpg')).sort_by { |f| File.mtime(f) }
49
- end
50
-
51
- def jpg_images_today
52
- jpg_images.select { |f| Date.parse(File.mtime(f).to_s) == Date.today }
53
- end
54
-
55
- def raw_image(image_file_type = 'jpg')
56
- File.join loldir, "tmp_snapshot.#{image_file_type}"
57
- end
58
-
59
- def main_image(commit_sha, image_file_type = 'jpg')
60
- File.join loldir, "#{commit_sha}.#{image_file_type}"
61
- end
62
-
63
- def video_loc
64
- File.join(loldir, 'tmp_video.mov')
65
- end
66
-
67
- def frames_loc
68
- File.join(loldir, 'tmp_frames')
45
+ def capture_path(ext = 'jpg')
46
+ File.join loldir, "raw_capture.#{ext}"
69
47
  end
70
48
 
71
49
  def list_plugins
@@ -11,11 +11,11 @@ module Lolcommits
11
11
  if ENV['LOLCOMMITS_CAPTURER']
12
12
  const_get(ENV['LOLCOMMITS_CAPTURER'])
13
13
  elsif platform_mac?
14
- animate ? CaptureMacAnimated : CaptureMac
14
+ animate ? CaptureMacVideo : CaptureMac
15
15
  elsif platform_linux?
16
- animate ? CaptureLinuxAnimated : CaptureLinux
16
+ animate ? CaptureLinuxVideo : CaptureLinux
17
17
  elsif platform_windows?
18
- animate ? CaptureWindowsAnimated : CaptureWindows
18
+ animate ? CaptureWindowsVideo : CaptureWindows
19
19
  elsif platform_cygwin?
20
20
  CaptureCygwin
21
21
  else
@@ -123,7 +123,7 @@ module Lolcommits
123
123
  # TODO: handle other platforms here (linux/windows) e.g with ffmpeg -list_devices
124
124
  return unless Platform.platform_mac?
125
125
 
126
- capturer = Lolcommits::CaptureMacAnimated.new
126
+ capturer = Lolcommits::CaptureMacVideo.new
127
127
  `#{capturer.executable_path} -l`
128
128
  end
129
129
  end
@@ -76,13 +76,13 @@ module Lolcommits
76
76
  # uniform puts and print for plugins
77
77
  # dont puts or print if the runner wants to be silent (stealth mode)
78
78
  def puts(*args)
79
- return if runner && runner.capture_stealth
79
+ return if runner&.capture_stealth
80
80
 
81
81
  super(*args)
82
82
  end
83
83
 
84
84
  def print(*args)
85
- return if runner && runner.capture_stealth
85
+ return if runner&.capture_stealth
86
86
 
87
87
  super(*args)
88
88
  end
@@ -31,7 +31,7 @@ module Lolcommits
31
31
  # value is returned.
32
32
  def prompt_autocomplete_hash(prompt, items, name: 'name', value: 'value', suggest_words: 5)
33
33
  words = items.map { |item| item[name] }.sort
34
- puts "e.g. #{words.take(suggest_words).join(', ')}" if suggest_words > 0
34
+ puts "e.g. #{words.take(suggest_words).join(', ')}" if suggest_words.positive?
35
35
  completed_input = gets_autocomplete(prompt, words)
36
36
  items.find { |item| item[name] == completed_input }[value]
37
37
  end
@@ -1,126 +1,195 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'lolcommits/platform'
4
+ require 'lolcommits/animated_gif'
4
5
 
5
6
  module Lolcommits
6
7
  class Runner
7
- attr_accessor :capture_delay, :capture_stealth, :capture_device, :message,
8
- :sha, :snapshot_loc, :main_image, :config, :vcs_info,
9
- :capture_animate
8
+ attr_accessor :capture_delay, :capture_stealth, :capture_device,
9
+ :capture_duration, :capture_path, :capture_video,
10
+ :capture_gif, :sha, :message, :config, :vcs_info,
11
+ :lolcommit_path, :lolcommit_gif_path
10
12
 
11
13
  def initialize(attributes = {})
12
14
  attributes.each do |attr, val|
13
15
  send("#{attr}=", val)
14
16
  end
15
17
 
16
- return unless sha.nil? || message.nil?
17
-
18
18
  if GitInfo.repo_root?
19
19
  self.vcs_info = GitInfo.new
20
20
  elsif MercurialInfo.repo_root?
21
21
  self.vcs_info = MercurialInfo.new
22
- else
23
- raise('Unknown VCS')
24
22
  end
25
23
 
26
- self.sha = vcs_info.sha if sha.nil?
27
- self.message = vcs_info.message if message.nil?
28
- end
24
+ self.sha = sha || vcs_info.sha
25
+ self.message = message || vcs_info.message
29
26
 
30
- def execute_plugins_for(hook)
31
- debug "#{self.class}: running all enabled plugin hooks for #{hook}"
32
- enabled_plugins.each do |plugin|
33
- if plugin.valid_configuration?
34
- plugin.send("run_#{hook}")
35
- else
36
- puts "Warning: skipping plugin #{plugin.name} (invalid configuration, fix with: lolcommits --config -p #{plugin.name})"
37
- end
38
- end
27
+ self.capture_path = config.capture_path(lolcommit_ext)
28
+ self.lolcommit_path = config.sha_path(sha, lolcommit_ext)
29
+ self.lolcommit_gif_path = config.sha_path(sha, 'gif') if capture_gif
39
30
  end
40
31
 
41
- # wrap run to handle things that should happen before and after
42
- # this used to be handled with ActiveSupport::Callbacks, but
43
- # now we're just using a simple procedural list
44
32
  def run
45
- # do plugins that need to happen before capture
46
33
  execute_plugins_for(:pre_capture)
47
34
 
48
- # do main capture to snapshot_loc
35
+ # main capture
49
36
  run_capture
50
37
 
51
- # check capture succeded, file must exist
52
- if File.exist?(snapshot_loc)
53
- ## resize snapshot first
54
- resize_snapshot!
38
+ # capture must exist to run post capture methods
39
+ unless File.exist?(capture_path)
40
+ raise 'failed to capture any image or video!'
41
+ end
42
+
43
+ run_post_capture
44
+ run_capture_ready
45
+ rescue StandardError => e
46
+ debug("#{e.class}: #{e.message}")
47
+ exit 1
48
+ ensure
49
+ debug 'running cleanup'
50
+ FileUtils.rm_f(capture_path)
51
+ end
55
52
 
56
- # execute post_capture plugins, use to alter the capture
57
- execute_plugins_for(:post_capture)
53
+ # return MiniMagick overlay png for manipulation (or create one)
54
+ def overlay
55
+ @overlay ||= begin
56
+ source_path = capture_image? ? lolcommit_path : capture_path
57
+ unless File.exist?(source_path)
58
+ raise "too early to overlay, capture doesn't exist yet"
59
+ end
58
60
 
59
- # execute capture_ready plugins, capture is ready for export/sharing
60
- execute_plugins_for(:capture_ready)
61
+ base = MiniMagick::Image.open(source_path)
62
+ png_tempfile = MiniMagick::Utilities.tempfile('.png')
63
+ debug("creating a new empty overlay png for lolcommit (#{base.dimensions.join('x')})")
61
64
 
62
- # clean away any tmp files
63
- cleanup!
64
- else
65
- debug 'Runner: failed to capture a snapshot'
66
- exit 1
65
+ MiniMagick::Tool::Convert.new do |i|
66
+ i.size "#{base.width}x#{base.height}"
67
+ i.xc 'transparent'
68
+ i << png_tempfile.path
69
+ end
70
+
71
+ MiniMagick::Image.open(png_tempfile.path)
72
+ end
73
+ end
74
+
75
+ # backward compatibility with earlier plugin releases
76
+ # remove this when all plugins target 0.14+
77
+ def main_image
78
+ capture_gif ? lolcommit_gif_path : lolcommit_path
79
+ end
80
+
81
+ private
82
+
83
+ def execute_plugins_for(hook)
84
+ debug "running all enabled #{hook} plugin hooks"
85
+ enabled_plugins.each do |plugin|
86
+ if plugin.valid_configuration?
87
+ plugin.send("run_#{hook}")
88
+ else
89
+ puts "Warning: skipping plugin #{plugin.name} (invalid configuration, fix with: lolcommits --config -p #{plugin.name})"
90
+ end
67
91
  end
68
92
  end
69
93
 
70
- # the main capture
94
+ def capture_image?
95
+ capture_duration.zero?
96
+ end
97
+
71
98
  def run_capture
72
99
  puts '*** Preserving this moment in history.' unless capture_stealth
73
- self.snapshot_loc = config.raw_image(image_file_type)
74
- self.main_image = config.main_image(sha, image_file_type)
75
-
76
- capturer = Platform.capturer_class(capture_animated?).new(
100
+ capturer = Platform.capturer_class(!capture_image?).new(
101
+ capture_path: capture_path,
77
102
  capture_device: capture_device,
78
103
  capture_delay: capture_delay,
79
- snapshot_location: snapshot_loc,
80
- video_location: config.video_loc,
81
- frames_location: config.frames_loc,
82
- animated_duration: capture_animate
104
+ capture_duration: capture_duration
83
105
  )
84
106
  capturer.capture
85
107
  end
86
108
 
87
- def capture_animated?
88
- capture_animate > 0
89
- end
109
+ def run_post_capture
110
+ resize_captured_image if capture_image?
90
111
 
91
- private
112
+ execute_plugins_for(:post_capture)
92
113
 
93
- def enabled_plugins
94
- @enabled_plugins ||= config.plugin_manager.enabled_plugins_for(self)
114
+ # apply overlay if present, or cp video to lolcommit_path
115
+ if @overlay
116
+ apply_overlay
117
+ elsif !capture_image?
118
+ FileUtils.cp(capture_path, lolcommit_path)
119
+ end
120
+
121
+ # optionally create animated gif
122
+ return unless capture_gif
123
+
124
+ AnimatedGif.new.create(
125
+ video_path: lolcommit_path,
126
+ output_path: lolcommit_gif_path
127
+ )
128
+
129
+ # done if we are capturing both video and gif
130
+ return if capture_video
131
+
132
+ # remove video and assign var (if only capturing gif)
133
+ FileUtils.rm_f(lolcommit_path)
134
+ self.lolcommit_path = lolcommit_gif_path
95
135
  end
96
136
 
97
- def image_file_type
98
- capture_animated? ? 'gif' : 'jpg'
137
+ def run_capture_ready
138
+ debug "lolcommit_path: #{lolcommit_path}"
139
+ debug "lolcommit_gif_path: #{lolcommit_gif_path}"
140
+ execute_plugins_for(:capture_ready)
99
141
  end
100
142
 
101
- def resize_snapshot!
102
- debug 'Runner: resizing snapshot'
103
- image = MiniMagick::Image.open(snapshot_loc)
104
- if image[:width] > 640 || image[:height] > 480
105
- # this is hacky resize-to-fill
143
+ def resize_captured_image
144
+ image = MiniMagick::Image.open(capture_path)
145
+
146
+ if image.width > 640 || image.height > 480
147
+ debug "resizing raw image (#{image.dimensions.join('x')}) to #{lolcommit_path} (640x480)"
148
+ # hacky resize to fill bounds
106
149
  image.combine_options do |c|
107
150
  c.resize '640x480^'
108
151
  c.gravity 'center'
109
152
  c.extent '640x480'
110
153
  end
111
- debug "Runner: writing resized image to #{snapshot_loc}"
112
- image.write snapshot_loc
154
+ image.write(lolcommit_path)
155
+ else
156
+ debug "no resize needed, copying raw image to #{lolcommit_path} (640x480)"
157
+ FileUtils.cp(capture_path, lolcommit_path)
113
158
  end
114
- debug "Runner: copying resized image to #{main_image}"
115
- FileUtils.cp(snapshot_loc, main_image)
116
159
  end
117
160
 
118
- def cleanup!
119
- debug 'Runner: running cleanup'
120
- # clean up the captured image and any other raw assets
121
- FileUtils.rm(snapshot_loc)
122
- FileUtils.rm_f(config.video_loc)
123
- FileUtils.rm_rf(config.frames_loc)
161
+ def apply_overlay
162
+ debug 'applying overlay to lolcommit'
163
+ if capture_image?
164
+ MiniMagick::Image.open(lolcommit_path).composite(overlay) do |c|
165
+ c.gravity 'center'
166
+ end.write(lolcommit_path)
167
+ else
168
+ system_call "ffmpeg -v quiet -nostats -i #{capture_path} -i #{overlay.path} \
169
+ -filter_complex overlay=0:0 \
170
+ -y #{lolcommit_path}"
171
+ end
172
+ end
173
+
174
+ def lolcommit_ext
175
+ if capture_image?
176
+ 'jpg'
177
+ else
178
+ 'mp4'
179
+ end
180
+ end
181
+
182
+ def enabled_plugins
183
+ @enabled_plugins ||= config.plugin_manager.enabled_plugins_for(self)
184
+ end
185
+
186
+ def system_call(call_str, capture_output = false)
187
+ debug "making system call for \n #{call_str}"
188
+ capture_output ? `#{call_str}` : system(call_str)
189
+ end
190
+
191
+ def debug(message)
192
+ super("#{self.class}: #{message}")
124
193
  end
125
194
  end
126
195
  end