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.
Files changed (92) hide show
  1. data/FAQ +12 -0
  2. data/LICENSE +5 -0
  3. data/README +7 -0
  4. data/Rakefile +30 -0
  5. data/TODO +106 -0
  6. data/VERSION +1 -0
  7. data/bin/bad_digit10.bmp +0 -0
  8. data/bin/bad_digit11.bmp +0 -0
  9. data/bin/bad_digit12.bmp +0 -0
  10. data/bin/bad_digit13.bmp +0 -0
  11. data/bin/bad_digit14.bmp +0 -0
  12. data/bin/bad_digit15.bmp +0 -0
  13. data/bin/bad_digit16.bmp +0 -0
  14. data/bin/bad_digit17.bmp +0 -0
  15. data/bin/bad_digit18.bmp +0 -0
  16. data/bin/bad_digit19.bmp +0 -0
  17. data/bin/bad_digit2.bmp +0 -0
  18. data/bin/bad_digit20.bmp +0 -0
  19. data/bin/bad_digit21.bmp +0 -0
  20. data/bin/bad_digit22.bmp +0 -0
  21. data/bin/bad_digit3.bmp +0 -0
  22. data/bin/bad_digit4.bmp +0 -0
  23. data/bin/bad_digit5.bmp +0 -0
  24. data/bin/bad_digit6.bmp +0 -0
  25. data/bin/bad_digit7.bmp +0 -0
  26. data/bin/bad_digit8.bmp +0 -0
  27. data/bin/bad_digit9.bmp +0 -0
  28. data/bin/hours.bmp +0 -0
  29. data/bin/minute_ones.bmp +0 -0
  30. data/bin/minute_tens.bmp +0 -0
  31. data/bin/scene-skipper +58 -0
  32. data/bin/second_ones.bmp +0 -0
  33. data/bin/second_tens.bmp +0 -0
  34. data/ext/mkrf_conf.rb +5 -0
  35. data/lib/blanker.rb +54 -0
  36. data/lib/keyboard_input.rb +45 -0
  37. data/lib/mouse.rb +60 -0
  38. data/lib/muter.rb +48 -0
  39. data/lib/ocr.rb +57 -0
  40. data/lib/overlayer.rb +341 -0
  41. data/lib/screen_tracker.rb +160 -0
  42. data/spec/common.rb +43 -0
  43. data/spec/convert_image.rb +8 -0
  44. data/spec/images/4.bmp +0 -0
  45. data/spec/images/black.bmp +0 -0
  46. data/spec/images/colon.bmp +0 -0
  47. data/spec/images/hulu_0.bmp +0 -0
  48. data/spec/images/hulu_2.bmp +0 -0
  49. data/spec/images/hulu_2_4.bmp +0 -0
  50. data/spec/images/hulu_3.bmp +0 -0
  51. data/spec/images/hulu_3_4.bmp +0 -0
  52. data/spec/images/hulu_4.bmp +0 -0
  53. data/spec/images/hulu_4_4.bmp +0 -0
  54. data/spec/images/hulu_5.bmp +0 -0
  55. data/spec/images/hulu_7.bmp +0 -0
  56. data/spec/images/hulu_slash.bmp +0 -0
  57. data/spec/images/vlc_0.bmp +0 -0
  58. data/spec/images/vlc_2_6.bmp +0 -0
  59. data/spec/images/vlc_4.bmp +0 -0
  60. data/spec/images/vlc_5.bmp +0 -0
  61. data/spec/images/vlc_6.bmp +0 -0
  62. data/spec/images/vlc_9.bmp +0 -0
  63. data/spec/images/vlc_colon.bmp +0 -0
  64. data/spec/mouse_forever.rb +2 -0
  65. data/spec/open.bat +1 -0
  66. data/spec/silence.wav +0 -0
  67. data/spec/spec.blanker.rb +35 -0
  68. data/spec/spec.keyboard_input.rb +56 -0
  69. data/spec/spec.mouse.rb +11 -0
  70. data/spec/spec.muter.rb +33 -0
  71. data/spec/spec.ocr.rb +33 -0
  72. data/spec/spec.overlayer.rb +331 -0
  73. data/spec/spec.screen_tracker.rb +211 -0
  74. data/spec/test_yaml.yml +4 -0
  75. data/vendor/gocr048.exe +0 -0
  76. data/zamples/players/captures/hulu full screen non hour.jpg +0 -0
  77. data/zamples/players/captures/hulu full screen over hour.jpg +0 -0
  78. data/zamples/players/captures/silence.bmp +0 -0
  79. data/zamples/players/captures/vlc grab over one hour file over one hour play.bmp +0 -0
  80. data/zamples/players/captures/vlc2.bmp +0 -0
  81. data/zamples/players/captures/vlc_full_screen_slider under one hour.bmp +0 -0
  82. data/zamples/players/captures/youtube full screen big screen.jpg +0 -0
  83. data/zamples/players/how_to +21 -0
  84. data/zamples/players/hulu_full_screened_over_an_hour.yml +23 -0
  85. data/zamples/players/vlc_full_screened.yml +6 -0
  86. data/zamples/players/vlc_full_screened_over_hour.yml +23 -0
  87. data/zamples/players/vlc_non_full_screened.yml +19 -0
  88. data/zamples/players/vlc_non_full_screened_under_an_hour.yml +19 -0
  89. data/zamples/scene_lists/disney_cars.yml +13 -0
  90. data/zamples/scene_lists/happy_feet.yml +7 -0
  91. data/zamples/scene_lists/mute_list.yml +15 -0
  92. 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
@@ -0,0 +1,11 @@
1
+ require 'rubygems'
2
+ require 'sane'
3
+ require_relative '../lib/mouse'
4
+
5
+ begin
6
+ Timeout::timeout(2) {
7
+ Mouse::jitter_forever_in_own_thread.join
8
+ }
9
+ rescue
10
+ end
11
+ puts 'mouse should have moved...'
@@ -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
@@ -0,0 +1,4 @@
1
+ title: Forever Strong
2
+ :mutes:
3
+ 2.0 : 3.0
4
+ 4.0 : 5.0
Binary file
Binary file