sensible-cinema 0.6.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.
- data/FAQ +12 -0
- data/LICENSE +5 -0
- data/README +7 -0
- data/Rakefile +30 -0
- data/TODO +106 -0
- data/VERSION +1 -0
- data/bin/bad_digit10.bmp +0 -0
- data/bin/bad_digit11.bmp +0 -0
- data/bin/bad_digit12.bmp +0 -0
- data/bin/bad_digit13.bmp +0 -0
- data/bin/bad_digit14.bmp +0 -0
- data/bin/bad_digit15.bmp +0 -0
- data/bin/bad_digit16.bmp +0 -0
- data/bin/bad_digit17.bmp +0 -0
- data/bin/bad_digit18.bmp +0 -0
- data/bin/bad_digit19.bmp +0 -0
- data/bin/bad_digit2.bmp +0 -0
- data/bin/bad_digit20.bmp +0 -0
- data/bin/bad_digit21.bmp +0 -0
- data/bin/bad_digit22.bmp +0 -0
- data/bin/bad_digit3.bmp +0 -0
- data/bin/bad_digit4.bmp +0 -0
- data/bin/bad_digit5.bmp +0 -0
- data/bin/bad_digit6.bmp +0 -0
- data/bin/bad_digit7.bmp +0 -0
- data/bin/bad_digit8.bmp +0 -0
- data/bin/bad_digit9.bmp +0 -0
- data/bin/hours.bmp +0 -0
- data/bin/minute_ones.bmp +0 -0
- data/bin/minute_tens.bmp +0 -0
- data/bin/scene-skipper +58 -0
- data/bin/second_ones.bmp +0 -0
- data/bin/second_tens.bmp +0 -0
- data/ext/mkrf_conf.rb +5 -0
- data/lib/blanker.rb +54 -0
- data/lib/keyboard_input.rb +45 -0
- data/lib/mouse.rb +60 -0
- data/lib/muter.rb +48 -0
- data/lib/ocr.rb +57 -0
- data/lib/overlayer.rb +341 -0
- data/lib/screen_tracker.rb +160 -0
- data/spec/common.rb +43 -0
- data/spec/convert_image.rb +8 -0
- data/spec/images/4.bmp +0 -0
- data/spec/images/black.bmp +0 -0
- data/spec/images/colon.bmp +0 -0
- data/spec/images/hulu_0.bmp +0 -0
- data/spec/images/hulu_2.bmp +0 -0
- data/spec/images/hulu_2_4.bmp +0 -0
- data/spec/images/hulu_3.bmp +0 -0
- data/spec/images/hulu_3_4.bmp +0 -0
- data/spec/images/hulu_4.bmp +0 -0
- data/spec/images/hulu_4_4.bmp +0 -0
- data/spec/images/hulu_5.bmp +0 -0
- data/spec/images/hulu_7.bmp +0 -0
- data/spec/images/hulu_slash.bmp +0 -0
- data/spec/images/vlc_0.bmp +0 -0
- data/spec/images/vlc_2_6.bmp +0 -0
- data/spec/images/vlc_4.bmp +0 -0
- data/spec/images/vlc_5.bmp +0 -0
- data/spec/images/vlc_6.bmp +0 -0
- data/spec/images/vlc_9.bmp +0 -0
- data/spec/images/vlc_colon.bmp +0 -0
- data/spec/mouse_forever.rb +2 -0
- data/spec/open.bat +1 -0
- data/spec/silence.wav +0 -0
- data/spec/spec.blanker.rb +35 -0
- data/spec/spec.keyboard_input.rb +56 -0
- data/spec/spec.mouse.rb +11 -0
- data/spec/spec.muter.rb +33 -0
- data/spec/spec.ocr.rb +33 -0
- data/spec/spec.overlayer.rb +331 -0
- data/spec/spec.screen_tracker.rb +211 -0
- data/spec/test_yaml.yml +4 -0
- data/vendor/gocr048.exe +0 -0
- data/zamples/players/captures/hulu full screen non hour.jpg +0 -0
- data/zamples/players/captures/hulu full screen over hour.jpg +0 -0
- data/zamples/players/captures/silence.bmp +0 -0
- data/zamples/players/captures/vlc grab over one hour file over one hour play.bmp +0 -0
- data/zamples/players/captures/vlc2.bmp +0 -0
- data/zamples/players/captures/vlc_full_screen_slider under one hour.bmp +0 -0
- data/zamples/players/captures/youtube full screen big screen.jpg +0 -0
- data/zamples/players/how_to +21 -0
- data/zamples/players/hulu_full_screened_over_an_hour.yml +23 -0
- data/zamples/players/vlc_full_screened.yml +6 -0
- data/zamples/players/vlc_full_screened_over_hour.yml +23 -0
- data/zamples/players/vlc_non_full_screened.yml +19 -0
- data/zamples/players/vlc_non_full_screened_under_an_hour.yml +19 -0
- data/zamples/scene_lists/disney_cars.yml +13 -0
- data/zamples/scene_lists/happy_feet.yml +7 -0
- data/zamples/scene_lists/mute_list.yml +15 -0
- metadata +286 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/common')
|
|
2
|
+
require_relative '../lib/keyboard_input'
|
|
3
|
+
|
|
4
|
+
describe KeyboardInput do
|
|
5
|
+
|
|
6
|
+
class Go
|
|
7
|
+
@time = 58
|
|
8
|
+
def self.cur_time
|
|
9
|
+
@time += 1
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.got
|
|
13
|
+
@got
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
@muted = true
|
|
17
|
+
class << self
|
|
18
|
+
attr_accessor :muted
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.status
|
|
22
|
+
@muted = !@muted
|
|
23
|
+
if @muted
|
|
24
|
+
"muted"
|
|
25
|
+
else
|
|
26
|
+
"unmuted"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.keyboard_input input
|
|
31
|
+
@got = input
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
before do
|
|
36
|
+
@a = KeyboardInput.new Go
|
|
37
|
+
Go.muted = true
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "should display on one line" do
|
|
41
|
+
@a.get_line_printout.should include("\b\b\b")
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "should display whether muted or not" do
|
|
45
|
+
@a.get_line_printout.should include("unmuted")
|
|
46
|
+
@a.get_line_printout.should_not include("unmuted")
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "should translate keys to characters" do
|
|
50
|
+
@a.handle_keystroke 77
|
|
51
|
+
Go.got.should == "M"
|
|
52
|
+
@a.handle_keystroke 109
|
|
53
|
+
Go.got.should == "m"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
end
|
data/spec/spec.mouse.rb
ADDED
data/spec/spec.muter.rb
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + "/common"
|
|
2
|
+
require_relative '../lib/muter'
|
|
3
|
+
|
|
4
|
+
describe 'manual muter' do
|
|
5
|
+
# functional test
|
|
6
|
+
|
|
7
|
+
3.times {
|
|
8
|
+
Muter.mute!
|
|
9
|
+
puts 'muted'
|
|
10
|
+
sleep 1
|
|
11
|
+
Muter.unmute!
|
|
12
|
+
puts 'unmuted'
|
|
13
|
+
sleep 1
|
|
14
|
+
}
|
|
15
|
+
# these rest *should* be able to pass...
|
|
16
|
+
|
|
17
|
+
Muter.mute!
|
|
18
|
+
Muter.mute!
|
|
19
|
+
puts 'silence'
|
|
20
|
+
sleep 1
|
|
21
|
+
Muter.unmute!
|
|
22
|
+
puts 'non silence'
|
|
23
|
+
sleep 1
|
|
24
|
+
Muter.unmute!
|
|
25
|
+
puts 'non silence'
|
|
26
|
+
sleep 1
|
|
27
|
+
puts 'single takes'
|
|
28
|
+
p Benchmark.realtime { 1.times{Muter.hit_volume_down_key}}
|
|
29
|
+
puts 'triple takes'
|
|
30
|
+
p Benchmark.realtime { 1.times{Muter.unmute!}} # 0.00023848s
|
|
31
|
+
# seems actually like reasonable speed
|
|
32
|
+
Muter.unmute!
|
|
33
|
+
end
|
data/spec/spec.ocr.rb
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/common'
|
|
2
|
+
require_relative "../lib/ocr"
|
|
3
|
+
|
|
4
|
+
describe OCR do
|
|
5
|
+
|
|
6
|
+
it "should be able to output help output" do
|
|
7
|
+
OCR.version.should_not be_blank
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it "should be able to grab some digits" do
|
|
11
|
+
success = true
|
|
12
|
+
for file in Dir['images/*[0-9].bmp']
|
|
13
|
+
options = {}
|
|
14
|
+
options[:should_invert] = true if file =~ /hulu/
|
|
15
|
+
file =~ /(.)\.bmp/
|
|
16
|
+
expected_digit = $1.to_i
|
|
17
|
+
if OCR.identify_digit(File.binread(file), options) != expected_digit
|
|
18
|
+
p "fail:" + file
|
|
19
|
+
success = false
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
fail unless success
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "should be able to grab a colon" do
|
|
26
|
+
OCR.identify_digit(File.binread("images/colon.bmp"), :might_be_colon => true).should == ":"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "should return nil if it can't identify a digit" do
|
|
30
|
+
OCR.identify_digit(File.binread("images/black.bmp")).should be_nil
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/common')
|
|
2
|
+
require_relative '../lib/overlayer'
|
|
3
|
+
|
|
4
|
+
# tell it not to actually mute during testing...
|
|
5
|
+
$DEBUG = true
|
|
6
|
+
|
|
7
|
+
def start_good_blank
|
|
8
|
+
assert !@o.blank?
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def start_bad_blank
|
|
12
|
+
assert @o.blank?
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
describe OverLayer do
|
|
17
|
+
|
|
18
|
+
before do
|
|
19
|
+
File.write 'temp.yml', YAML.dump({:mutes => {2.0 => 4.0}} )
|
|
20
|
+
@o = OverLayer.new('temp.yml')
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
after do
|
|
24
|
+
Thread.join_all_others
|
|
25
|
+
File.delete 'temp.yml'
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def start_good
|
|
29
|
+
assert !@o.muted?
|
|
30
|
+
sleep 1
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def start_bad
|
|
34
|
+
assert @o.muted? # note this uses @o!
|
|
35
|
+
sleep 1
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it 'should reject overlapping settings...I guess'
|
|
39
|
+
|
|
40
|
+
it 'should be able to mute' do
|
|
41
|
+
# several combinations...
|
|
42
|
+
assert !@o.muted?
|
|
43
|
+
@o.mute!
|
|
44
|
+
assert @o.muted?
|
|
45
|
+
@o.unmute!
|
|
46
|
+
assert !@o.muted?
|
|
47
|
+
@o.mute!
|
|
48
|
+
assert @o.muted?
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
context 'given you know when to start' do
|
|
52
|
+
|
|
53
|
+
it 'should mute based on time' do
|
|
54
|
+
@o.start_thread
|
|
55
|
+
# make sure we enter the mute section
|
|
56
|
+
sleep 2.25
|
|
57
|
+
start_bad
|
|
58
|
+
sleep 1
|
|
59
|
+
start_good
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it 'should handle multiple mutes in a row' do
|
|
63
|
+
File.write 'temp.yml', YAML.dump({:mutes => {2.0 => 4.0, 5.0 => 7.0}})
|
|
64
|
+
@o = OverLayer.new 'temp.yml'
|
|
65
|
+
@o.start_thread
|
|
66
|
+
sleep 2.5
|
|
67
|
+
start_bad # 1s
|
|
68
|
+
sleep 2 # => 5.5
|
|
69
|
+
start_bad
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it 'should be able to mute teeny sequences' do
|
|
73
|
+
File.write 'temp.yml', YAML.dump({:mutes => {0.0001 => 0.0002, 1.0 => 1.0001}})
|
|
74
|
+
o = OverLayer.new 'temp.yml'
|
|
75
|
+
o.continue_until_past_all false
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
context 'startup' do
|
|
80
|
+
it 'should allow you to change the current time' do
|
|
81
|
+
@o.start_thread
|
|
82
|
+
sleep 0.1 # wow ruby is slow...
|
|
83
|
+
assert @o.cur_time > 0
|
|
84
|
+
@o.set_seconds 5
|
|
85
|
+
sleep 0.1
|
|
86
|
+
assert @o.cur_time > 5
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it 'should be able to hit keys to affect input' do
|
|
90
|
+
@o = OverLayer.new 'test_yaml.yml'
|
|
91
|
+
@o.cur_time
|
|
92
|
+
@o.keyboard_input 'm'
|
|
93
|
+
assert @o.cur_time > 59
|
|
94
|
+
@o.keyboard_input 'M'
|
|
95
|
+
assert @o.cur_time < 59
|
|
96
|
+
60.times {
|
|
97
|
+
@o.keyboard_input 's'
|
|
98
|
+
}
|
|
99
|
+
assert @o.cur_time > 59
|
|
100
|
+
60.times {
|
|
101
|
+
@o.keyboard_input 'S'
|
|
102
|
+
}
|
|
103
|
+
assert @o.cur_time < 59
|
|
104
|
+
600.times {
|
|
105
|
+
@o.keyboard_input 't'
|
|
106
|
+
}
|
|
107
|
+
assert @o.cur_time > 59
|
|
108
|
+
600.times {
|
|
109
|
+
@o.keyboard_input 'T'
|
|
110
|
+
}
|
|
111
|
+
assert @o.cur_time < 59
|
|
112
|
+
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it 'should have help output' do
|
|
118
|
+
@o.status.should include("MmSs")
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it 'should allow for real yaml files somehow and use it' do
|
|
122
|
+
# 2 - 3 , 4-5 should be muted
|
|
123
|
+
@o = OverLayer.new 'test_yaml.yml'
|
|
124
|
+
@o.start_thread
|
|
125
|
+
start_good # takes 1s
|
|
126
|
+
sleep 1.25
|
|
127
|
+
start_bad
|
|
128
|
+
start_good
|
|
129
|
+
start_bad
|
|
130
|
+
start_good
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def write_yaml yaml
|
|
134
|
+
File.write 'temp.yml', yaml
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
it 'should allow for 1:00.0 minute style input' do
|
|
138
|
+
write_yaml <<YAML
|
|
139
|
+
:mutes:
|
|
140
|
+
"0:02.0" : "0:03.0"
|
|
141
|
+
YAML
|
|
142
|
+
@o = OverLayer.new 'temp.yml'
|
|
143
|
+
@o.start_thread
|
|
144
|
+
start_good
|
|
145
|
+
start_good
|
|
146
|
+
sleep 0.25
|
|
147
|
+
start_bad
|
|
148
|
+
start_good
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
it "should reload the YAML file on the fly to allow for editing it" do
|
|
152
|
+
# start it with one far later
|
|
153
|
+
write_yaml <<YAML
|
|
154
|
+
:mutes:
|
|
155
|
+
"0:11.0" : "0:12.0"
|
|
156
|
+
YAML
|
|
157
|
+
@o = OverLayer.new 'temp.yml'
|
|
158
|
+
@o.start_thread
|
|
159
|
+
start_good
|
|
160
|
+
write_yaml <<YAML
|
|
161
|
+
:mutes:
|
|
162
|
+
"0:00.0" : "0:01.5"
|
|
163
|
+
YAML
|
|
164
|
+
# go forward a tenth
|
|
165
|
+
# should reload it...
|
|
166
|
+
@o.keyboard_input 'T'
|
|
167
|
+
sleep 0.1 # blug
|
|
168
|
+
start_bad
|
|
169
|
+
start_good
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
it "should translate yaml well" do
|
|
173
|
+
yaml = <<-YAML
|
|
174
|
+
:mutes:
|
|
175
|
+
"0:02.0" : "0:03.0"
|
|
176
|
+
:blank_outs:
|
|
177
|
+
"0:02.0" : "0:03.0"
|
|
178
|
+
YAML
|
|
179
|
+
out = OverLayer.translate_yaml yaml
|
|
180
|
+
out[:mutes].to_a.first.should == [2.0, 3.0]
|
|
181
|
+
out[:blank_outs].to_a.first.should == [2.0, 3.0]
|
|
182
|
+
yaml = <<-YAML
|
|
183
|
+
:mutes:
|
|
184
|
+
"1:02.11" : "1:03.0"
|
|
185
|
+
YAML
|
|
186
|
+
out = OverLayer.translate_yaml yaml
|
|
187
|
+
out[:mutes].to_a.first.should == [62.11, 63.0]
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
it "should translate strings as well as symbols" do
|
|
191
|
+
yaml = <<-YAML
|
|
192
|
+
mutes:
|
|
193
|
+
"1" : "3
|
|
194
|
+
YAML
|
|
195
|
+
out = OverLayer.translate_yaml yaml
|
|
196
|
+
out[:mutes].to_a.first.should == [1, 3]
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
it "should disallow negative length intervals"
|
|
200
|
+
|
|
201
|
+
it "should allow for 1:01:00.0 (double colon) style input" do
|
|
202
|
+
write_yaml <<-YAML
|
|
203
|
+
:mutes:
|
|
204
|
+
"1:00.11" : "1:03.0"
|
|
205
|
+
YAML
|
|
206
|
+
@o = OverLayer.new 'temp.yml'
|
|
207
|
+
@o.start_thread
|
|
208
|
+
start_good
|
|
209
|
+
@o.set_seconds 61
|
|
210
|
+
sleep 0.1 # ruby rox again!
|
|
211
|
+
start_bad
|
|
212
|
+
sleep 2
|
|
213
|
+
start_good
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
it "should be able to tell the player to sync to the closest second when the screen only changes" do
|
|
217
|
+
@o.start_thread
|
|
218
|
+
start = Time.now
|
|
219
|
+
while((Time.now - start) < 3) do
|
|
220
|
+
@o.timestamp_changed nil, nil
|
|
221
|
+
sleep 0.1
|
|
222
|
+
end
|
|
223
|
+
@o.cur_time.should be < 1
|
|
224
|
+
sleep 1
|
|
225
|
+
10.times { @o.timestamp_changed(nil, nil) }
|
|
226
|
+
@o.cur_time.should be >= 1
|
|
227
|
+
sleep 0.6
|
|
228
|
+
@o.timestamp_changed nil, nil
|
|
229
|
+
@o.cur_time.should be >= 2
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
it "should be able to handle it when the sync message includes a new timestamp" do
|
|
233
|
+
@o.start_thread
|
|
234
|
+
@o.timestamp_changed "1:00:01", 0
|
|
235
|
+
@o.cur_time.should be > 60*60
|
|
236
|
+
@o.timestamp_changed "0:00:01", 0
|
|
237
|
+
@o.cur_time.should be < 60*60
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
it "should handle deltas to created timestamps" do
|
|
241
|
+
@o.start_thread
|
|
242
|
+
@o.timestamp_changed "1:00:00", 1
|
|
243
|
+
@o.cur_time.should be >= 60*60 + 1
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
context "should handle blanks, too" do
|
|
247
|
+
|
|
248
|
+
it "should be able to discover next states well" do
|
|
249
|
+
for type in [:blank_outs, :mutes] do
|
|
250
|
+
@o = OverLayer.new_raw({type => {2.0 => 4.0}})
|
|
251
|
+
@o.discover_state(type, 3).should == [2.0, 4.0, true]
|
|
252
|
+
@o.discover_state(type, 0.5).should == [2.0, 4.0, false]
|
|
253
|
+
@o.discover_state(type, 5).should == [nil, nil, :done]
|
|
254
|
+
@o.discover_state(type, 2.0).should == [2.0, 4.0, true]
|
|
255
|
+
@o.discover_state(type, 4.0).should == [nil, nil, :done]
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
context "with a list of blanks" do
|
|
260
|
+
|
|
261
|
+
it "should blank" do
|
|
262
|
+
@o = OverLayer.new_raw({:blank_outs => {2.0 => 4.0}})
|
|
263
|
+
|
|
264
|
+
@o.start_thread
|
|
265
|
+
start_good_blank
|
|
266
|
+
sleep 1
|
|
267
|
+
start_good_blank
|
|
268
|
+
sleep 1.1
|
|
269
|
+
start_bad_blank
|
|
270
|
+
sleep 2
|
|
271
|
+
start_good_blank
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
def at time
|
|
276
|
+
@o.stub!(:cur_time) {
|
|
277
|
+
time
|
|
278
|
+
}
|
|
279
|
+
yield
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
context "mixed blanks and others" do
|
|
283
|
+
it "should allow for mixed" do
|
|
284
|
+
@o = OverLayer.new_raw({:mutes => {2.0 => 3.5}, :blank_outs => {3.0 => 4.0}})
|
|
285
|
+
at(1.5) do
|
|
286
|
+
@o.cur_time.should == 1.5
|
|
287
|
+
@o.get_current_state.should == [false, false, 2.0]
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
at(2.0) do
|
|
291
|
+
@o.get_current_state.should == [true, false, 3.0]
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
at(3.0) do
|
|
295
|
+
@o.get_current_state.should == [true, true, 3.5]
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
at(3.75) do
|
|
299
|
+
@o.get_current_state.should == [false, true, 4.0]
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
at(4) do
|
|
303
|
+
@o.get_current_state.should == [false, false, :done]
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
end
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
it "should not fail with verbose on, after it's past next states" do
|
|
310
|
+
at(500_000) do
|
|
311
|
+
@o.status.should == "Current time: 138:53:20.0 no more actions after this point... (HhMmSsTtdvq): "
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
it "should be human readable" do
|
|
319
|
+
@o.translate_time_to_human_readable(3600).should == "1:00:00.0"
|
|
320
|
+
@o.translate_time_to_human_readable(3600.0).should == "1:00:00.0"
|
|
321
|
+
@o.translate_time_to_human_readable(3601).should == "1:00:01.0"
|
|
322
|
+
@o.translate_time_to_human_readable(3661).should == "1:01:01.0"
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
it "should accept human readable input" do
|
|
326
|
+
o = OverLayer.new 'temp.yml', "01:01.5"
|
|
327
|
+
o.cur_time.should be == 61.5
|
|
328
|
+
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
end
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/common')
|
|
2
|
+
require_relative '../lib/overlayer'
|
|
3
|
+
require_relative '../lib/screen_tracker'
|
|
4
|
+
require 'pathname'
|
|
5
|
+
|
|
6
|
+
describe ScreenTracker do
|
|
7
|
+
|
|
8
|
+
if RUBY_PLATFORM =~ /java/
|
|
9
|
+
it "is pending a java bug..."
|
|
10
|
+
else
|
|
11
|
+
before(:all) do
|
|
12
|
+
begin
|
|
13
|
+
Win32::Screenshot.window(/silence.wav/, 0) {}
|
|
14
|
+
rescue
|
|
15
|
+
# this way we'll only have one up...
|
|
16
|
+
@pid1 = IO.popen('open.bat').pid # jruby can't open it directly yet
|
|
17
|
+
sleep 2
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
before do
|
|
22
|
+
@a = ScreenTracker.new(/silence.*VLC/,10,10,20,20)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "can take a regex or string" do
|
|
26
|
+
ScreenTracker.new(/silence.*VLC/,10,10,20,20)
|
|
27
|
+
ScreenTracker.new("silence",10,10,20,20)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "should be able to grab a picture from screen coords...probably from the current active window" do
|
|
31
|
+
@a.get_bmp.should_not be_nil
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "should loop if unable to find the right window" do
|
|
35
|
+
proc {
|
|
36
|
+
Timeout::timeout(1) do
|
|
37
|
+
ScreenTracker.new("unknown window",10,10,20,20)
|
|
38
|
+
end
|
|
39
|
+
}.should raise_error(Timeout::Error)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "should be at least somewhat fast" do
|
|
43
|
+
Benchmark.realtime { @a.get_bmp }.should be < 0.3
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "should not allow for negative widths" do
|
|
47
|
+
proc {ScreenTracker.new("VLC",10,10,-20,20)}.should raise_error
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "should disallow size 0 widths" do
|
|
51
|
+
proc {ScreenTracker.new("VLC",10,10,0,0)}.should raise_error
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "should have different bmp if sizes different" do
|
|
55
|
+
a = ScreenTracker.new("VLC",10,10,5,5)
|
|
56
|
+
assert a.get_relative_coords == [10,10,15,15]
|
|
57
|
+
b = ScreenTracker.new("VLC",10,10,50,50)
|
|
58
|
+
assert a.get_bmp != b.get_bmp
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it "should allow for straight desktop if they specify Desktop or desktop" do
|
|
62
|
+
a = ScreenTracker.new("desktop",0,0,100,100)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
context "negative numbers should result in an offset" do
|
|
66
|
+
|
|
67
|
+
it "should allow for negative sizes" do
|
|
68
|
+
a = ScreenTracker.new("VLC",-10,10,5,5)
|
|
69
|
+
a.get_bmp
|
|
70
|
+
a = ScreenTracker.new("VLC",-10,-10,10,10) # right to the edge
|
|
71
|
+
a.get_bmp
|
|
72
|
+
a = ScreenTracker.new("VLC",10,-10,5,5)
|
|
73
|
+
a.get_bmp
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it "should assign right coords" do
|
|
77
|
+
a = ScreenTracker.new("VLC",-10,-10,5,5)
|
|
78
|
+
a.get_bmp
|
|
79
|
+
x,y,x2,y2=a.get_relative_coords
|
|
80
|
+
hwnd = Win32::Screenshot::BitmapMaker.hwnd("VLC")
|
|
81
|
+
always_zero, always_zero, max_x, max_y = Win32::Screenshot::BitmapMaker.dimensions_for(hwnd)
|
|
82
|
+
x.should == max_x-10
|
|
83
|
+
y.should == max_y-10
|
|
84
|
+
x2.should == x+5
|
|
85
|
+
y2.should == y+5
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it "should look different with negative than with positive" do
|
|
89
|
+
a = ScreenTracker.new("VLC",10,10,50,50)
|
|
90
|
+
b = ScreenTracker.new("VLC",10,10,50,50)
|
|
91
|
+
c = ScreenTracker.new("VLC",-99,-99,50,50)
|
|
92
|
+
assert a.get_bmp == b.get_bmp
|
|
93
|
+
assert c.get_relative_coords != b.get_relative_coords
|
|
94
|
+
cb = c.get_bmp
|
|
95
|
+
bb = b.get_bmp
|
|
96
|
+
c.get_bmp.length == b.get_bmp.length
|
|
97
|
+
assert c.get_bmp != b.get_bmp
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it "should fail with out of bounds or zero sizes" do
|
|
101
|
+
proc { a = ScreenTracker.new(/silence.*VLC/,-10,10,20,20) }.should raise_error
|
|
102
|
+
proc { a = ScreenTracker.new(/silence.*VLC/,10,-10,20,20) }.should raise_error
|
|
103
|
+
proc { a = ScreenTracker.new(/silence.*VLC/,-10,10,0,2) }.should raise_error
|
|
104
|
+
proc { a = ScreenTracker.new(/silence.*VLC/,10,10,2,0) }.should raise_error
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# lodo: this 7 looks rather redundant...
|
|
110
|
+
it "should parse yaml appropro" do
|
|
111
|
+
yaml = <<-YAML
|
|
112
|
+
name: VLC
|
|
113
|
+
x: 32
|
|
114
|
+
y: 34
|
|
115
|
+
width: 100
|
|
116
|
+
height: 20
|
|
117
|
+
digits:
|
|
118
|
+
:hours:
|
|
119
|
+
:minute_tens:
|
|
120
|
+
- -90
|
|
121
|
+
- 7
|
|
122
|
+
:minute_ones:
|
|
123
|
+
- -82
|
|
124
|
+
- 7
|
|
125
|
+
:second_tens:
|
|
126
|
+
- -72
|
|
127
|
+
- 7
|
|
128
|
+
:second_ones:
|
|
129
|
+
- -66
|
|
130
|
+
- 7
|
|
131
|
+
YAML
|
|
132
|
+
a = ScreenTracker.new_from_yaml(yaml,nil)
|
|
133
|
+
a.get_relative_coords.should == [32,34,132,54]
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it "should be able to dump its contents" do
|
|
137
|
+
@a.dump_bmp
|
|
138
|
+
assert File.exist?('dump.bmp') && File.exist?('all.dump.bmp')
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
context "given a real player that is moving" do
|
|
142
|
+
|
|
143
|
+
before do
|
|
144
|
+
@a = ScreenTracker.new("silence.wav", -111, -16, 86, 13)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
it "should be able to poll the screen to know when something changes" do
|
|
148
|
+
@a.wait_till_next_change
|
|
149
|
+
# it updates every 1 second...
|
|
150
|
+
Benchmark.realtime { @a.wait_till_next_change }.should be > 0.2
|
|
151
|
+
@a.dump_bmp # for debugging...
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
context "using OCR" do
|
|
155
|
+
|
|
156
|
+
before do
|
|
157
|
+
# vlc_non_full_screened_under_an_hour.yml
|
|
158
|
+
@a = ScreenTracker.new("silence.wav", -111, -16, 86, 13,
|
|
159
|
+
{:hours => nil, :minute_tens => [-90,7], :minute_ones => [-82, 7], :second_tens => [-72, 7], :second_ones => [-66, 7]} )
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
it "should be able to snapshot digits" do
|
|
163
|
+
@a.dump_bmp
|
|
164
|
+
Pathname.new('minute_tens.bmp').should exist
|
|
165
|
+
Pathname.new('minute_tens.bmp').size.should be > 0
|
|
166
|
+
Pathname.new('hours.bmp').should_not exist
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
it "should use OCR against the changes appropriately" do
|
|
170
|
+
output = @a.wait_till_next_change
|
|
171
|
+
output[0].should be_a(String)
|
|
172
|
+
output[0].should include("00:0")# let's hope it runs quickly...
|
|
173
|
+
output[0].should match(/[1-9]/)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
context "with an OCR that can change willy-nilly from hour to second" do
|
|
177
|
+
it "should ocr slash...[in other]"
|
|
178
|
+
it "with VLC should be able to recognize when it goes past an hour somehow...probably by presence of hourly colon" # might already do this
|
|
179
|
+
it "should work with hulu too, because of ads"
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
it "should be able to use invert on images" do
|
|
183
|
+
@a = ScreenTracker.new("silence.wav", -111, -16, 86, 13,
|
|
184
|
+
{:should_invert => true, :hours => nil, :minute_tens => [-90,7], :minute_ones => [-82, 7], :second_tens => [-72, 7], :second_ones => [-66, 7]} )
|
|
185
|
+
got_it = nil
|
|
186
|
+
OCR.stub!(:identify_digit) {|*args|
|
|
187
|
+
got_it = args
|
|
188
|
+
}
|
|
189
|
+
@a.identify_digit('some binary bitmap data')
|
|
190
|
+
got_it[1][:should_invert].should be_true
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
after(:all) do
|
|
196
|
+
begin
|
|
197
|
+
# bring redcar to the foreground
|
|
198
|
+
# this seg faults on windows 7 for me for some reason when run inside the editor itself...swt bug?
|
|
199
|
+
unless Socket.gethostname == "PACKRD-1GK7V"
|
|
200
|
+
Win32::Screenshot.window(/universal/, 0) rescue nil
|
|
201
|
+
end
|
|
202
|
+
Process.kill 9, @pid1 rescue nil # need this re-started each time or the screen won't change for the screen changing test
|
|
203
|
+
FileUtils.rm_rf Dir['*.bmp'] unless $DEBUG
|
|
204
|
+
rescue => e
|
|
205
|
+
puts 'got after bug:', e # until this bug is fixed... http://github.com/rspec/rspec-core/issues#issue/21
|
|
206
|
+
throw e
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
end
|
data/spec/test_yaml.yml
ADDED
data/vendor/gocr048.exe
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|