sensible-cinema 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|