headless-muse 1.1.0 → 1.1.1
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/.travis/setup.sh +2 -2
- data/README.md +3 -1
- data/headless.gemspec +3 -3
- data/lib/headless/cli_util.rb +15 -4
- data/lib/headless/video/video_recorder.rb +9 -1
- data/spec/cli_util_spec.rb +33 -2
- data/spec/features/capture_video_spec.rb +25 -0
- data/spec/features/headless_spec.rb +13 -0
- data/spec/video_recorder_spec.rb +18 -2
- metadata +5 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a2bebc3311027182542cd8a5374d6f56074b9954
|
|
4
|
+
data.tar.gz: 9a26b8fb2b5b68ff99423af6501e2ceca992ec90
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 976b2176d38bc395b96e574e6252a893f4e44df9d9d0920c5f46c542bbe1737b37725fb6f2d060672985fce9e88598bf8892861a6b02e29d0311dd741cb36d56
|
|
7
|
+
data.tar.gz: 0ee6c18e1b05285179dd1f884896d8fd39b2b496e628042a61237183b8dcdcb660329b1d55eb563337f5a9b2ff3aa21652310811ca21d6d00a375f3a758256c8
|
data/.travis/setup.sh
CHANGED
|
@@ -3,7 +3,7 @@ case "$FFMPEG_VERSION" in
|
|
|
3
3
|
2.3)
|
|
4
4
|
sudo add-apt-repository ppa:archivematica/externals -y
|
|
5
5
|
sudo apt-get update -q
|
|
6
|
-
sudo apt-get install ffmpeg
|
|
6
|
+
sudo apt-get install ffmpeg fluxbox
|
|
7
7
|
;;
|
|
8
8
|
|
|
9
9
|
1.2)
|
|
@@ -11,5 +11,5 @@ case "$FFMPEG_VERSION" in
|
|
|
11
11
|
;;
|
|
12
12
|
*)
|
|
13
13
|
sudo apt-get update -q
|
|
14
|
-
sudo apt-get install ffmpeg
|
|
14
|
+
sudo apt-get install ffmpeg fluxbox
|
|
15
15
|
esac
|
data/README.md
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
# Headless
|
|
2
|
+
[](http://badge.fury.io/rb/headless-muse)
|
|
2
3
|
[](https://travis-ci.org/pgeraghty/headless)
|
|
3
4
|
[](https://coveralls.io/r/pgeraghty/headless?branch=master)
|
|
5
|
+
[](https://codeclimate.com/github/pgeraghty/headless)
|
|
4
6
|
|
|
5
7
|
# This fork
|
|
6
8
|
|
|
7
|
-
This fork is the source of the [headless-muse gem]().
|
|
9
|
+
This fork is the source of the [headless-muse gem](https://rubygems.org/gems/headless-muse).
|
|
8
10
|
|
|
9
11
|
## Notes by original author (Leonid Shevtsov)
|
|
10
12
|
|
data/headless.gemspec
CHANGED
|
@@ -3,16 +3,16 @@ Gem::Specification.new do |s|
|
|
|
3
3
|
s.email = 'muse@appsthatcould.be'
|
|
4
4
|
|
|
5
5
|
s.name = 'headless-muse'
|
|
6
|
-
s.version = '1.1.
|
|
6
|
+
s.version = '1.1.1'
|
|
7
7
|
s.summary = 'Ruby headless display interface'
|
|
8
8
|
|
|
9
9
|
s.description = <<-EOF
|
|
10
10
|
Headless is a Ruby interface for Xvfb. It allows you to create a headless display straight from Ruby code, hiding some low-level action.
|
|
11
|
-
It can also capture video and audio via ffmpeg and take screenshots.
|
|
11
|
+
It can also capture video and audio via ffmpeg (including the latest versions) and take screenshots using ImageMagick.
|
|
12
12
|
EOF
|
|
13
13
|
s.requirements = 'Xvfb'
|
|
14
14
|
s.homepage = 'https://github.com/pgeraghty/headless'
|
|
15
|
-
s.license = 'MIT'
|
|
15
|
+
s.license = 'MIT'
|
|
16
16
|
s.files = `git ls-files`.split("\n")
|
|
17
17
|
|
|
18
18
|
s.add_development_dependency 'rake'
|
data/lib/headless/cli_util.rb
CHANGED
|
@@ -23,10 +23,8 @@ class Headless
|
|
|
23
23
|
Process.kill(0, pid)
|
|
24
24
|
pid
|
|
25
25
|
rescue Errno::ESRCH
|
|
26
|
-
|
|
26
|
+
false
|
|
27
27
|
end
|
|
28
|
-
else
|
|
29
|
-
nil
|
|
30
28
|
end
|
|
31
29
|
end
|
|
32
30
|
|
|
@@ -43,9 +41,10 @@ class Headless
|
|
|
43
41
|
end
|
|
44
42
|
|
|
45
43
|
def self.kill_process(pid_filename, options={})
|
|
44
|
+
options[:sig] ||= 'TERM'
|
|
46
45
|
if pid = self.read_pid(pid_filename)
|
|
47
46
|
begin
|
|
48
|
-
Process.kill
|
|
47
|
+
Process.kill options[:sig], pid
|
|
49
48
|
Process.wait pid if options[:wait]
|
|
50
49
|
rescue Errno::ESRCH
|
|
51
50
|
# no such process; assume it's already killed
|
|
@@ -60,5 +59,17 @@ class Headless
|
|
|
60
59
|
# pid file already removed
|
|
61
60
|
end
|
|
62
61
|
end
|
|
62
|
+
|
|
63
|
+
def self.signal_process(pid_filename, signal, options={})
|
|
64
|
+
if pid = self.read_pid(pid_filename)
|
|
65
|
+
begin
|
|
66
|
+
Process.kill signal, pid
|
|
67
|
+
true
|
|
68
|
+
rescue Errno::ESRCH
|
|
69
|
+
# no such process; assume it's already killed
|
|
70
|
+
false
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
63
74
|
end
|
|
64
75
|
end
|
|
@@ -58,8 +58,16 @@ class Headless
|
|
|
58
58
|
end
|
|
59
59
|
end
|
|
60
60
|
|
|
61
|
+
def pause
|
|
62
|
+
CliUtil.signal_process(@pid_file_path, 'STOP')
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def resume
|
|
66
|
+
CliUtil.signal_process(@pid_file_path, 'CONT')
|
|
67
|
+
end
|
|
68
|
+
|
|
61
69
|
def stop_and_save(path)
|
|
62
|
-
CliUtil.kill_process(@pid_file_path, :wait => true)
|
|
70
|
+
CliUtil.kill_process(@pid_file_path, :wait => true, :sig => 'INT')
|
|
63
71
|
if File.exists? @tmp_file_path
|
|
64
72
|
begin
|
|
65
73
|
FileUtils.mv(@tmp_file_path, path)
|
data/spec/cli_util_spec.rb
CHANGED
|
@@ -57,9 +57,40 @@ describe Headless::CliUtil do
|
|
|
57
57
|
subject.class.read_pid('/tmp/.headless_ffmpeg_99.pid').should eq(999999999999)
|
|
58
58
|
end
|
|
59
59
|
|
|
60
|
-
it 'returns
|
|
60
|
+
it 'returns false after a rescued error when process does not exist' do
|
|
61
61
|
Process.stub(:kill).and_raise(Errno::ESRCH)
|
|
62
|
-
subject.class.read_pid('/tmp/.headless_ffmpeg_99.pid').should eq(
|
|
62
|
+
subject.class.read_pid('/tmp/.headless_ffmpeg_99.pid').should eq(false)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
describe 'signal_process' do
|
|
67
|
+
let(:pidfile) { '/tmp/pid' }
|
|
68
|
+
let(:fakepid) { 999999999999 }
|
|
69
|
+
|
|
70
|
+
before do
|
|
71
|
+
Process.stub(:kill)
|
|
72
|
+
File.stub(:read).and_return(fakepid.to_s)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it 'reads PID file' do
|
|
76
|
+
#File.should_receive(:read).with(pidfile).and_return('')
|
|
77
|
+
File.stub(:read).and_return('')
|
|
78
|
+
subject.class.should_receive(:read_pid).with(pidfile).and_return(nil)
|
|
79
|
+
subject.class.signal_process(pidfile, 'CONT').should eq(nil)
|
|
63
80
|
end
|
|
81
|
+
|
|
82
|
+
it 'sends signal to process' do
|
|
83
|
+
Process.should_receive(:kill).with('CONT', fakepid)
|
|
84
|
+
subject.class.should_receive(:read_pid).with(pidfile).and_return(fakepid)
|
|
85
|
+
subject.class.signal_process(pidfile, 'CONT').should eq(true)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it 'returns false after a rescued error when process does not exist' do
|
|
89
|
+
Process.stub(:kill).and_raise(Errno::ESRCH)
|
|
90
|
+
subject.class.should_receive(:read_pid).with(pidfile).and_return(fakepid)
|
|
91
|
+
subject.class.signal_process(pidfile, 'STOP').should eq(false)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
|
|
64
95
|
end
|
|
65
96
|
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Headless::VideoRecorder do
|
|
4
|
+
it 'should capture 10s of video on request' do
|
|
5
|
+
h = Headless.new(:display => 99, :reuse => true, :dimensions => '1280x720x24')
|
|
6
|
+
|
|
7
|
+
capture_file = '/tmp/screen-capture-mpeg4.mkv'
|
|
8
|
+
log = '/tmp/ffmpeg_test.log'
|
|
9
|
+
|
|
10
|
+
sleep 5 # give Xvfb some time
|
|
11
|
+
`DISPLAY=:99 fluxbox > /dev/null 2>&1 &`
|
|
12
|
+
sleep 3
|
|
13
|
+
`ffmpeg -f x11grab -r 30 -s 1280x720 -i :99.0 -vcodec mpeg4 -qscale:v 2 -threads 1 -y -t 10 #{capture_file} > #{log} 2>&1`
|
|
14
|
+
expected_duration =
|
|
15
|
+
if h.video.guess_ffmpeg_version! > Gem::Version.new(1.2)
|
|
16
|
+
/time=00:00:10/
|
|
17
|
+
else
|
|
18
|
+
/time=10/
|
|
19
|
+
end
|
|
20
|
+
expect(File.read log).to match(expected_duration)
|
|
21
|
+
expect(`ffprobe #{capture_file} 2>&1 | grep Duration`).to match(/Duration: 00:00:10/)
|
|
22
|
+
`rm #{capture_file}`
|
|
23
|
+
expect { h.destroy }.not_to raise_error
|
|
24
|
+
end
|
|
25
|
+
end if Headless::CliUtil.application_exists?('Xvfb') && Headless::CliUtil.application_exists?('ffmpeg')
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Headless do
|
|
4
|
+
let(:h) { Headless.new }
|
|
5
|
+
|
|
6
|
+
it 'should start Xvfb when instantiated' do
|
|
7
|
+
expect(h).to be_instance_of(Headless)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it 'should destroy Xvfb when requested' do
|
|
11
|
+
expect { h.destroy }.not_to raise_error
|
|
12
|
+
end
|
|
13
|
+
end if Headless::CliUtil.application_exists?('Xvfb')
|
data/spec/video_recorder_spec.rb
CHANGED
|
@@ -32,7 +32,7 @@ describe Headless::VideoRecorder do
|
|
|
32
32
|
end
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
-
context
|
|
35
|
+
context 'stopping, pausing and resuming video recording' do
|
|
36
36
|
let(:tmpfile) { '/tmp/ci.mov' }
|
|
37
37
|
let(:filename) { '/tmp/test.mov' }
|
|
38
38
|
let(:pidfile) { '/tmp/pid' }
|
|
@@ -45,7 +45,7 @@ describe Headless::VideoRecorder do
|
|
|
45
45
|
|
|
46
46
|
describe "using #stop_and_save" do
|
|
47
47
|
it "stops video recording and saves file" do
|
|
48
|
-
Headless::CliUtil.should_receive(:kill_process).with(pidfile, :wait => true)
|
|
48
|
+
Headless::CliUtil.should_receive(:kill_process).with(pidfile, :wait => true, :sig => 'INT')
|
|
49
49
|
File.should_receive(:exists?).with(tmpfile).and_return(true)
|
|
50
50
|
FileUtils.should_receive(:mv).with(tmpfile, filename)
|
|
51
51
|
|
|
@@ -75,6 +75,22 @@ describe Headless::VideoRecorder do
|
|
|
75
75
|
end
|
|
76
76
|
end
|
|
77
77
|
|
|
78
|
+
describe 'using #pause' do
|
|
79
|
+
it 'pauses video recording' do
|
|
80
|
+
Headless::CliUtil.should_receive(:signal_process).with(pidfile, 'STOP')
|
|
81
|
+
|
|
82
|
+
expect(subject.pause).to eq(nil)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
describe 'using #resume' do
|
|
87
|
+
it 'resumes video recording' do
|
|
88
|
+
Headless::CliUtil.should_receive(:signal_process).with(pidfile, 'CONT')
|
|
89
|
+
|
|
90
|
+
expect(subject.resume).to eq(nil)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
78
94
|
describe '#capture_running?' do
|
|
79
95
|
it 'returns false unless the PID file exists' do
|
|
80
96
|
Headless::CliUtil.should_receive(:read_pid).with(pidfile)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: headless-muse
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.1.
|
|
4
|
+
version: 1.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Leonid Shevtsov
|
|
@@ -10,7 +10,7 @@ authors:
|
|
|
10
10
|
autorequire:
|
|
11
11
|
bindir: bin
|
|
12
12
|
cert_chain: []
|
|
13
|
-
date: 2014-08-
|
|
13
|
+
date: 2014-08-18 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: rake
|
|
@@ -56,7 +56,7 @@ dependencies:
|
|
|
56
56
|
version: '0'
|
|
57
57
|
description: |2
|
|
58
58
|
Headless is a Ruby interface for Xvfb. It allows you to create a headless display straight from Ruby code, hiding some low-level action.
|
|
59
|
-
It can also capture video and audio via ffmpeg and take screenshots.
|
|
59
|
+
It can also capture video and audio via ffmpeg (including the latest versions) and take screenshots using ImageMagick.
|
|
60
60
|
email: muse@appsthatcould.be
|
|
61
61
|
executables: []
|
|
62
62
|
extensions: []
|
|
@@ -75,6 +75,8 @@ files:
|
|
|
75
75
|
- lib/headless/cli_util.rb
|
|
76
76
|
- lib/headless/video/video_recorder.rb
|
|
77
77
|
- spec/cli_util_spec.rb
|
|
78
|
+
- spec/features/capture_video_spec.rb
|
|
79
|
+
- spec/features/headless_spec.rb
|
|
78
80
|
- spec/headless_spec.rb
|
|
79
81
|
- spec/spec_helper.rb
|
|
80
82
|
- spec/video_recorder_spec.rb
|