sensible-cinema 0.7.0 → 0.7.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +81 -30
- data/TODO +1 -3
- data/VERSION +1 -1
- data/bin/sensible-cinema +8 -6
- data/ext/mkrf_conf.rb +3 -0
- data/lib/blanker.rb +3 -3
- data/lib/file_chooser.rb +15 -8
- data/lib/ocr.rb +0 -2
- data/lib/overlayer.rb +80 -61
- data/lib/screen_tracker.rb +1 -3
- data/spec/{spec.blanker.rb → blanker.spec.rb} +0 -0
- data/spec/images/hulu_2_3.bmp +0 -0
- data/spec/images/hulu_8.bmp +0 -0
- data/spec/{spec.keyboard_input.rb → keyboard_input.spec.rb} +0 -0
- data/spec/{spec.mouse.rb → mouse.spec.rb} +0 -0
- data/spec/{spec.muter.rb → muter.spec.rb} +0 -0
- data/spec/{spec.ocr.rb → ocr.spec.orb} +0 -0
- data/spec/overlayer.spec.rb +378 -0
- data/spec/{spec.screen_tracker.rb → screen_tracker.spec.rb} +1 -2
- data/zamples/players/hulu_full_screen_total_length_over_an_hour.yml +4 -4
- data/zamples/scene_lists/example_scene_list.yml +4 -1
- data/zamples/scene_lists/{happy_feet.yml → happy_feet_dvd.yml} +0 -0
- data/zamples/scene_lists/star_trek_generations.yml +7 -0
- metadata +20 -18
- data/spec/spec.overlayer.rb +0 -331
data/README
CHANGED
@@ -1,17 +1,13 @@
|
|
1
|
-
|
1
|
+
Sensible-cinema is a program that aims to allow you to do arbitrary scene selection (i.e. "mute out" or "bleep out" bad scenes).
|
2
2
|
|
3
|
-
|
3
|
+
Currently it takes as input a list of known "skip-worthy" scenes (profanity, violence, annoying songs, whatever you don't like).
|
4
|
+
It then tracks the player you are using, as it is playing, and mutes or blanks out the system screen appropriately, during the scenes
|
5
|
+
specified.
|
4
6
|
|
5
|
-
|
6
|
-
It does this by leveraging existing players and controlling the system-wide volume, etc.
|
7
|
-
|
8
|
-
Currently it takes as input a list of known "skip-worthy" scenes (profanity, violence, whatever),
|
9
|
-
and tracks the player as it is playing, then mutes or blanks out the system screen appropriately, during those scenes.
|
10
|
-
|
11
|
-
Currently it works for hulu and VLC on windows. It also isn't hard to add new players (thanks Ruby and yaml!),
|
7
|
+
Currently it is known to work for for hulu and VLC playback on windows. It also isn't hard to add new players,
|
12
8
|
and probably wouldn't be super hard to add more operating systems.
|
13
9
|
|
14
|
-
|
10
|
+
The concept isn't new: http://en.wikipedia.org/wiki/Edit_decision_list
|
15
11
|
|
16
12
|
== How to use ==
|
17
13
|
|
@@ -19,42 +15,97 @@ Start playing your movie in its player, then startup sensible-cinema thus:
|
|
19
15
|
|
20
16
|
C:\> jruby -S sensible-cinema
|
21
17
|
|
22
|
-
It then prompts you for a scene list
|
18
|
+
It then prompts you for a scene list file (ex: bambi.yml),
|
19
|
+
and then subsequently for a player description file (ex: hulu_full_screen_with_total_length_over_an_hour.yml).
|
23
20
|
|
24
|
-
|
21
|
+
You could also specify those two filenames on the command-line, if desired, like
|
25
22
|
|
26
23
|
C:\> jruby -S sensible-cinema mute_list.yml player_description.yml
|
27
24
|
|
28
|
-
Sensible-cinema
|
29
|
-
|
25
|
+
Sensible-cinema will now run in your console window, screen tracking the player's timer to monitor the playback position
|
26
|
+
and react appropriately.
|
27
|
+
|
28
|
+
You'll know that it's working if, when you change the time of your player (ex: dragging it to a new spot in the playback),
|
29
|
+
the screen output in sensible-cinema's console should change to match the new time.
|
30
|
+
|
31
|
+
It is presumed that you'll then minimize the console window and enjoy the movie.
|
30
32
|
|
31
33
|
== How to install ==
|
32
34
|
|
33
|
-
First install jruby (in case you haven't already), from http://www.jruby.org
|
35
|
+
First you'll need to install jruby (in case you haven't already), from http://www.jruby.org
|
36
|
+
Make sure you check the box "add it to my path" or something similar to that.
|
34
37
|
|
35
|
-
Next install the gem
|
38
|
+
Next install the gem by either opening up the command window or hitting windows+r (run) and typing
|
36
39
|
|
37
|
-
C:\> jruby -S gem install sensible-cinema
|
40
|
+
C:\> jruby -S gem install sensible-cinema
|
38
41
|
|
39
|
-
it's jruby only currently (since jruby allows for proper thread concurrency, has easy GUI, and feels
|
40
|
-
It could theoretically be ported to MRI 1.9.x, if anybody
|
41
|
-
|
42
|
-
developed. I'm somewhat targeting Netflix' "play now", hence focusing thus far on windows.
|
42
|
+
it's jruby only currently (since jruby allows for proper thread concurrency, has an easy GUI, and feels actually sane on windows).
|
43
|
+
It could theoretically be ported to MRI 1.9.x, if anybody wanted to do so.
|
44
|
+
Also if anybody would be interested in porting this to Linux I'd be happy to collaborate.
|
43
45
|
|
46
|
+
You can test that it's installed by running it (see above) and selecting the "example_scene_list.yml", and
|
47
|
+
choosing the hulu player.
|
48
|
+
|
49
|
+
It will proceed do a few "demo" mutes and blank outs.
|
50
|
+
|
51
|
+
== How to use ==
|
52
|
+
|
53
|
+
To use it, first watch an DVD/online movie you'd like to create a scene-list for.
|
54
|
+
As questionable scenes occur, jot down their start and end times somewhere.
|
55
|
+
Then create an Edit Decision List (EDL) file that looks like this:
|
56
|
+
|
57
|
+
mutes:
|
58
|
+
"00:01:01.5" : "00:01:02.5" # mute from one minute, one second and a half to one minute, two seconds and a half
|
44
59
|
"01:00:00" : "01:01:02.5" # mute from exactly one hour to one hour, one minute, two seconds and a half will be muted.
|
60
|
+
blank_outs:
|
61
|
+
"00:15" : "00:18" # sultry scene from seconds 15 to 18 will be blanked out.
|
62
|
+
"01:00:00" : "01:01:02.5" # also blank out on of the muted scenes.
|
63
|
+
|
64
|
+
...
|
65
|
+
|
66
|
+
Here's an example with more detail
|
67
|
+
http://github.com/rdp/sensible-cinema/blob/master/zamples/scene_lists/example_scene_list.yml
|
68
|
+
|
69
|
+
Now save that file somewhere (I tend to save it with a .yml extension--you don't have to--.txt will do)
|
70
|
+
and remember where you saved it.
|
71
|
+
|
72
|
+
Now start sensible-cinema, see above, and browse to wherever you file is (the "home" icon might be useful to you), and
|
73
|
+
select it for your scene list. Also restart the movie.
|
74
|
+
|
75
|
+
Sensible-cinema will now use it as the edit decision list for the movie
|
76
|
+
as it plays it back. You could probably re-watch the movie and see if you got the timings right. A good excuse to
|
77
|
+
watch movies, what could be better?
|
78
|
+
|
79
|
+
Note also that don't have to watch the whole movie twice. You can create and test the scene list file on the fly.
|
80
|
+
To do so, first create a blank file, and choose it in sensible-cinema (even though it's blank).
|
81
|
+
Now "as you watch" the movie, you can edit the file, and any new changes should be picked up automatically.
|
82
|
+
So you could basically notice something you want to add to the list, add it to the file, then go back a few seconds in your
|
83
|
+
media player, and it should now be muted/blanked out automatically.
|
84
|
+
|
45
85
|
== FAQ ==
|
46
86
|
|
47
|
-
Q. Can I watch
|
87
|
+
Q. Can I watch movies this way on my TV, not just on my computer?
|
48
88
|
|
49
|
-
A. Not yet. Currently you'll either need to attach your computer to your TV
|
50
|
-
|
51
|
-
with
|
52
|
-
|
53
|
-
There
|
89
|
+
A. Not yet. Well maybe. Currently you'll either need to attach your computer to your TV
|
90
|
+
(buy some long cables, or a new graphics card, etc.)
|
91
|
+
or get some other computer that you can move closer to the TV and do the same (ex: buy a used older laptop with s-video out).
|
92
|
+
I'd be happy to do a linux port of sensible-cinema if anybody needs that for their dedicated TV computer.
|
93
|
+
There has also been some work toward getting your computer to stream what it plays "live" to your wii/ps3/xbox.
|
54
94
|
github message me if you're interested in trying it out.
|
55
95
|
|
96
|
+
Q. What movies are available to watch online?
|
97
|
+
|
98
|
+
A. Not many are available free (hulu, youtube have a few), but Netflix has quite a few. Plus you can watch your DVD's
|
99
|
+
on your computer monitor.
|
100
|
+
|
101
|
+
Q. Why does my mouse bounce up and down while this thing is playing?
|
102
|
+
|
103
|
+
A. This enables you to keep your on screen tracker visible, which allows sensible-cinema to track where you're at.
|
104
|
+
Message me if this bugs you too much and we'll see what we can do for it.
|
105
|
+
|
56
106
|
== Thanks ==
|
57
107
|
|
58
|
-
Thanks to Jarmo for the win32-screenshot gem, and mini_magick gem authors, jruby guys, etc.
|
108
|
+
Thanks to Jarmo for the win32-screenshot gem, and the mini_magick gem authors, jruby guys, etc.
|
109
|
+
Made programming this actually somewhat a pleasure.
|
59
110
|
|
60
111
|
== License ==
|
61
112
|
|
@@ -62,6 +113,6 @@ See the LICENSE for licensing, usage terms (gplv3).
|
|
62
113
|
|
63
114
|
== Feedback ==
|
64
115
|
|
65
|
-
Feedback welcome.
|
116
|
+
Feedback, including feature requests, welcome.
|
66
117
|
http://github.com/rdp/sensible-cinema
|
67
|
-
http://github.com/rdp
|
118
|
+
http://github.com/rdp me
|
data/TODO
CHANGED
@@ -32,7 +32,7 @@ PISH
|
|
32
32
|
|
33
33
|
can overlay with a "fuzzer-outer" for specific coordinates somehow or other...
|
34
34
|
|
35
|
-
advertise like to lay men
|
35
|
+
advertise like to lay men, to try to popularize
|
36
36
|
|
37
37
|
with VLC non full screen, it does the annoying mouse thing needlessly (which doesn't bug as much these days...)
|
38
38
|
|
@@ -96,8 +96,6 @@ Programmatically do all of the above, by driving a player with its real API.
|
|
96
96
|
auto start on DVD insertion (?)
|
97
97
|
and show appropriate scene-lists available based on title/md5 of something?
|
98
98
|
|
99
|
-
could have an easy
|
100
|
-
|
101
99
|
never do unless paid:
|
102
100
|
|
103
101
|
super easy streamer windows -> {XBOX360, wii, etc..} basically like playon, which appears to have no free equivalent, I guess, though you can
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.7.
|
1
|
+
0.7.1
|
data/bin/sensible-cinema
CHANGED
@@ -40,25 +40,26 @@ else
|
|
40
40
|
sleep 4
|
41
41
|
else
|
42
42
|
if !File.exist? scene_list.to_s
|
43
|
-
scene_list = FileChooser.choose_file("
|
43
|
+
scene_list = FileChooser.choose_file("SELECT SCENE LIST", __dir__ + "/../zamples/scene_lists")
|
44
44
|
end
|
45
45
|
unless scene_list
|
46
|
-
puts
|
46
|
+
puts "error: have to specify a scene list\n or specify \"test\" on the command line if you just want to snapshot your player"
|
47
47
|
exit 1
|
48
48
|
end
|
49
|
+
puts 'Selected scene list ' + File.basename(scene_list) + " (#{scene_list})", ''
|
49
50
|
overlay = OverLayer.new(scene_list)
|
50
|
-
|
51
|
+
|
51
52
|
end
|
52
53
|
|
53
54
|
player_description = ARGV.shift
|
54
|
-
if !File.exist?(player_description.to_s)
|
55
|
-
player_description = FileChooser.choose_file("
|
55
|
+
if !File.exist?(player_description.to_s)
|
56
|
+
player_description = FileChooser.choose_file("SELECT PLAYER (optional)", __dir__ + "/../zamples/players")
|
56
57
|
end
|
57
58
|
|
58
59
|
if File.exist? player_description.to_s
|
59
60
|
# this one doesn't use file updates, so pass it the string
|
60
61
|
Mouse.jitter_forever_in_own_thread
|
61
|
-
puts 'Selected player ' + player_description, ''
|
62
|
+
puts 'Selected player ' + File.basename(player_description) + " (#{player_description})", ''
|
62
63
|
screen_tracker = ScreenTracker.new_from_yaml File.binread(player_description), overlay
|
63
64
|
screen_tracker.dump_bmp if $VERBOSE
|
64
65
|
# exit early if we just wanted a screen dump...a little kludgey...
|
@@ -68,6 +69,7 @@ else
|
|
68
69
|
puts 'warning--not using any screen tracking...'
|
69
70
|
end
|
70
71
|
|
72
|
+
overlay.start_thread true
|
71
73
|
key_input = KeyboardInput.new overlay
|
72
74
|
key_input.start_thread # status thread
|
73
75
|
key_input.handle_keystrokes_forever # when this method exits, we want to exit fully...
|
data/ext/mkrf_conf.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
raise 'must be using jruby to be able to run this...at least for now' unless RUBY_PLATFORM =~ /java/
|
2
2
|
|
3
|
+
require 'win32/registry'
|
4
|
+
|
5
|
+
|
3
6
|
f = File.open(File.join(File.dirname(__FILE__), "Rakefile"), "w") # create dummy rakefile to indicate success
|
4
7
|
f.write("task :default\n")
|
5
8
|
f.close
|
data/lib/blanker.rb
CHANGED
@@ -8,8 +8,8 @@ class Blanker
|
|
8
8
|
JPanel = javax.swing.JPanel
|
9
9
|
|
10
10
|
def self.blank_full_screen!
|
11
|
-
|
12
|
-
frame = JFrame.new("
|
11
|
+
# a new screen each time as other jruby doesn't terminate as gracefully as we would like...
|
12
|
+
frame = JFrame.new("blanked section") # ltodo pass in param
|
13
13
|
frame.default_close_operation = JFrame::EXIT_ON_CLOSE
|
14
14
|
frame.set_location(0,0)
|
15
15
|
frame.set_size(2000, 2000) # ltodo better coords...
|
@@ -34,7 +34,7 @@ class Blanker
|
|
34
34
|
@fr.set_visible(true)
|
35
35
|
end
|
36
36
|
else
|
37
|
-
|
37
|
+
# MRI fake blanker :)
|
38
38
|
def self.blank_full_screen!
|
39
39
|
puts 'the screen is now...blank!'
|
40
40
|
end
|
data/lib/file_chooser.rb
CHANGED
@@ -1,18 +1,25 @@
|
|
1
|
+
require 'java'
|
2
|
+
|
1
3
|
module FileChooser
|
2
4
|
|
3
5
|
# show a popup dialog prompting for them to select a file
|
4
6
|
# pretty ugly
|
5
7
|
def choose_file(title, use_this_dir = nil)
|
6
|
-
|
7
|
-
fc.
|
8
|
-
|
8
|
+
|
9
|
+
fc = java.awt.FileDialog.new(nil, title)
|
10
|
+
if use_this_dir
|
11
|
+
# FileDialog only accepts it a certain way.
|
12
|
+
dir = File.expand_path(use_this_dir).gsub(File::Separator, File::ALT_SEPARATOR)
|
13
|
+
fc.setDirectory(dir)
|
14
|
+
end
|
9
15
|
# lodo allow for a FileFilter, too...
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
nil
|
16
|
+
Thread.new { sleep 2; fc.to_front } # it gets hidden, unfortunately
|
17
|
+
fc.show
|
18
|
+
if fc.get_file
|
19
|
+
out = fc.get_directory + '\\' + fc.get_file
|
15
20
|
end
|
21
|
+
fc.remove_notify # allow out app to exit
|
22
|
+
out
|
16
23
|
end
|
17
24
|
|
18
25
|
extend self
|
data/lib/ocr.rb
CHANGED
@@ -14,10 +14,8 @@ module OCR
|
|
14
14
|
# options are :might_be_colon, :should_invert
|
15
15
|
def identify_digit memory_bitmap, options = {}
|
16
16
|
if CACHE[memory_bitmap]
|
17
|
-
print 'h' if $DEBUG
|
18
17
|
return CACHE[memory_bitmap]
|
19
18
|
else
|
20
|
-
p 'ocr cache miss' if $DEBUG
|
21
19
|
end
|
22
20
|
might_be_colon = options[:might_be_colon]
|
23
21
|
should_invert = options[:should_invert]
|
data/lib/overlayer.rb
CHANGED
@@ -44,18 +44,21 @@ class OverLayer
|
|
44
44
|
Blanker.unblank_full_screen! unless $DEBUG
|
45
45
|
end
|
46
46
|
|
47
|
-
def
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
pps 'because old time', @file_mtime.to_f, '!= new time', new_time.to_f if $VERBOSE
|
53
|
-
@file_mtime = new_time # save 0.0002!
|
54
|
-
else
|
55
|
-
p 'matching time:', new_time if $VERBOSE
|
47
|
+
def check_reload_yaml
|
48
|
+
current_mtime = File.stat(@filename).mtime # save 0.0002!
|
49
|
+
if @file_mtime != current_mtime
|
50
|
+
reload_yaml!
|
51
|
+
@file_mtime = current_mtime
|
56
52
|
end
|
57
53
|
end
|
58
54
|
|
55
|
+
def reload_yaml!
|
56
|
+
@all_sequences = OverLayer.translate_yaml(File.read(@filename))
|
57
|
+
# LTODO... @all_sequences = @all_sequences.map{|k, v| v.sort!} etc. and validate...
|
58
|
+
puts '(re) loaded mute sequences from ' + File.basename(@filename) + ' as', pretty_sequences.pretty_inspect, "" unless $DEBUG && !$VERBOSE # I hate these during unit tests...
|
59
|
+
signal_change
|
60
|
+
end
|
61
|
+
|
59
62
|
def pretty_sequences
|
60
63
|
new_sequences = {}
|
61
64
|
@all_sequences.each{|type, values|
|
@@ -90,15 +93,28 @@ class OverLayer
|
|
90
93
|
end
|
91
94
|
|
92
95
|
def self.translate_yaml raw_yaml
|
93
|
-
|
96
|
+
begin
|
97
|
+
all = YAML.load(raw_yaml) || {}
|
98
|
+
|
99
|
+
rescue NoMethodError
|
100
|
+
p 'appears your file has a syntax error in it--perhaps missing quotation marks'
|
101
|
+
return
|
102
|
+
end
|
94
103
|
# now it's like {:mutes => {"1:02.0" => "1:3.0"}}
|
95
104
|
# translate to floats like 62.0 => 63.0
|
96
105
|
for type in [:mutes, :blank_outs]
|
97
106
|
maps = all[type] || all[type.to_s] || {}
|
98
107
|
new = {}
|
99
|
-
maps.each{|
|
108
|
+
maps.each{|start,endy|
|
100
109
|
# both are like 1:02.0
|
101
|
-
|
110
|
+
start = translate_string_to_seconds(start)
|
111
|
+
endy = translate_string_to_seconds(endy)
|
112
|
+
if start == 0 || endy == 0
|
113
|
+
p 'warning--possible error in the scene list someline not parsed! (NB if you want one to start at time 0 please use 0.0001)', start, endy unless $DEBUG
|
114
|
+
# drop it in bitbucket...
|
115
|
+
else
|
116
|
+
new[start] = endy
|
117
|
+
end
|
102
118
|
}
|
103
119
|
all.delete(type.to_s)
|
104
120
|
all[type] = new.sort
|
@@ -120,26 +136,15 @@ class OverLayer
|
|
120
136
|
out << "%04.1f" % seconds
|
121
137
|
end
|
122
138
|
|
123
|
-
|
124
|
-
|
125
|
-
if to_this_exact_string
|
126
|
-
set_seconds OverLayer.translate_string_to_seconds(to_this_exact_string) + delta
|
127
|
-
else
|
128
|
-
round_current_time_to_nearest_second
|
129
|
-
end
|
139
|
+
def timestamp_changed to_this_exact_string_might_be_nil, delta
|
140
|
+
set_seconds OverLayer.translate_string_to_seconds(to_this_exact_string_might_be_nil) + delta if to_this_exact_string_might_be_nil
|
130
141
|
end
|
131
142
|
|
132
|
-
def round_current_time_to_nearest_second
|
133
|
-
current_time = cur_time
|
134
|
-
better_time = current_time.round
|
135
|
-
set_seconds better_time
|
136
|
-
puts 'screen snapshot diff with time we thought it was was:' + (current_time - better_time).to_s if $VERBOSE
|
137
|
-
end
|
138
|
-
|
139
143
|
def self.translate_string_to_seconds s
|
140
|
-
# might actually already be a float
|
141
|
-
|
142
|
-
|
144
|
+
# might actually already be a float, or int, depending on the yaml
|
145
|
+
# int for 8 => 9 and also for 1:09 => 1:10
|
146
|
+
if s.is_a? Numeric
|
147
|
+
return s.to_f
|
143
148
|
end
|
144
149
|
|
145
150
|
# s is like 1:01:02.0
|
@@ -155,20 +160,28 @@ class OverLayer
|
|
155
160
|
|
156
161
|
# returns seconds it's at currently...
|
157
162
|
def cur_time
|
158
|
-
|
163
|
+
Time.now_f - @start_time
|
164
|
+
end
|
165
|
+
|
166
|
+
def cur_english_time
|
167
|
+
translate_time_to_human_readable(cur_time)
|
159
168
|
end
|
160
169
|
|
161
170
|
def status
|
162
|
-
time = "Current time: " +
|
171
|
+
time = "Current time: " + cur_english_time
|
163
172
|
begin
|
164
173
|
mute, blank, next_sig = get_current_state
|
165
174
|
if next_sig == :done
|
166
175
|
state = " no more actions after this point..."
|
167
176
|
else
|
168
|
-
state = " next action at #{translate_time_to_human_readable next_sig}s
|
177
|
+
state = " next action will be at #{translate_time_to_human_readable next_sig}s "
|
178
|
+
end
|
179
|
+
if blank? or muted?
|
180
|
+
state += "(" + [muted? ? "muted" : nil, blank? ? "blanked" : nil ].compact.join(' ') + ") "
|
169
181
|
end
|
170
182
|
end
|
171
|
-
|
183
|
+
check_reload_yaml
|
184
|
+
time + state + "(r,d,v,q to quit): "
|
172
185
|
end
|
173
186
|
|
174
187
|
def keyboard_input char
|
@@ -192,10 +205,13 @@ class OverLayer
|
|
192
205
|
when ' ' then
|
193
206
|
puts cur_time
|
194
207
|
return
|
208
|
+
when 'r' then
|
209
|
+
reload_yaml!
|
210
|
+
puts
|
211
|
+
return
|
195
212
|
else nil
|
196
213
|
end
|
197
214
|
if delta
|
198
|
-
reload_yaml!
|
199
215
|
set_seconds(cur_time + delta)
|
200
216
|
else
|
201
217
|
puts 'invalid char: [' + char + ']'
|
@@ -207,7 +223,14 @@ class OverLayer
|
|
207
223
|
seconds = [seconds, 0].max
|
208
224
|
@mutex.synchronize {
|
209
225
|
@start_time = Time.now_f - seconds
|
210
|
-
|
226
|
+
}
|
227
|
+
signal_change
|
228
|
+
end
|
229
|
+
|
230
|
+
def signal_change
|
231
|
+
@mutex.synchronize {
|
232
|
+
# tell the driver thread to wake up and re-check state.
|
233
|
+
# We're not super thread friendly but good enough for having two contact each other...
|
211
234
|
@cv.signal
|
212
235
|
}
|
213
236
|
end
|
@@ -220,7 +243,11 @@ class OverLayer
|
|
220
243
|
# end
|
221
244
|
|
222
245
|
def start_thread continue_forever = false
|
223
|
-
Thread.new { continue_until_past_all continue_forever }
|
246
|
+
@thread = Thread.new { continue_until_past_all continue_forever }
|
247
|
+
end
|
248
|
+
|
249
|
+
def kill_thread!
|
250
|
+
@thread.kill
|
224
251
|
end
|
225
252
|
|
226
253
|
# returns [start, end, active|:done]
|
@@ -273,17 +300,18 @@ class OverLayer
|
|
273
300
|
|
274
301
|
def continue_until_past_all continue_forever
|
275
302
|
if RUBY_VERSION < '1.9.2'
|
276
|
-
raise 'need 1.9.2+ for MRI' unless RUBY_PLATFORM =~ /java/
|
303
|
+
raise 'need 1.9.2+ for MRI for the mutex stuff' unless RUBY_PLATFORM =~ /java/
|
277
304
|
end
|
278
305
|
|
279
306
|
@mutex.synchronize {
|
280
307
|
loop {
|
281
308
|
muted, blanked, next_point = get_current_state
|
282
309
|
if next_point == :done
|
283
|
-
|
284
|
-
return # done!
|
285
|
-
else
|
310
|
+
if continue_forever
|
286
311
|
time_till_next_mute_starts = 1_000_000
|
312
|
+
else
|
313
|
+
#set_states! # for the unit tests' sake
|
314
|
+
return
|
287
315
|
end
|
288
316
|
else
|
289
317
|
time_till_next_mute_starts = next_point - cur_time
|
@@ -293,49 +321,40 @@ class OverLayer
|
|
293
321
|
|
294
322
|
@cv.wait(@mutex, time_till_next_mute_starts) if time_till_next_mute_starts > 0
|
295
323
|
pps 'just woke up from pre-mute wait at', Time.now_f if $VERBOSE
|
296
|
-
|
324
|
+
set_states!
|
297
325
|
}
|
298
326
|
}
|
299
327
|
end
|
300
328
|
|
329
|
+
def display_change change
|
330
|
+
puts ''
|
331
|
+
puts change + ' at ' + cur_english_time if $VERBOSE unless $DEBUG # too chatty for unit tests
|
332
|
+
end
|
333
|
+
|
301
334
|
def set_states!
|
302
335
|
should_be_muted, should_be_blank, next_point = get_current_state
|
303
336
|
|
304
337
|
if should_be_muted && !muted?
|
305
338
|
mute!
|
339
|
+
puts ''
|
340
|
+
display_change 'muted'
|
306
341
|
end
|
307
342
|
|
308
343
|
if !should_be_muted && muted?
|
309
|
-
unmute!
|
344
|
+
unmute!
|
345
|
+
display_change 'unmuted'
|
310
346
|
end
|
311
347
|
|
312
348
|
if should_be_blank && !blank?
|
313
349
|
blank!
|
350
|
+
display_change 'blanked'
|
314
351
|
end
|
315
352
|
|
316
353
|
if !should_be_blank && blank?
|
317
354
|
unblank!
|
355
|
+
display_change 'unblanked'
|
318
356
|
end
|
319
357
|
|
320
358
|
end
|
321
359
|
|
322
|
-
def something_has_possibly_changed
|
323
|
-
current = cur_time
|
324
|
-
muted, blanked, next_point = get_current_state
|
325
|
-
@muted = muted
|
326
|
-
@blanked = blanked
|
327
|
-
@endy = next_point
|
328
|
-
return if next_point == :done
|
329
|
-
if(current < next_point)
|
330
|
-
set_states!
|
331
|
-
duration_left = @endy - current
|
332
|
-
pps 'just muted it at', Time.now_f, current, 'for interval:', 'which is', duration_left, 'more s' if $VERBOSE
|
333
|
-
if duration_left > 0
|
334
|
-
@cv.wait(@mutex, duration_left) if duration_left > 0
|
335
|
-
end
|
336
|
-
pps 'done sleeping', duration_left, 'was muted unmuting now', Time.now_f if $VERBOSE
|
337
|
-
set_states!
|
338
|
-
end
|
339
|
-
end
|
340
|
-
|
341
360
|
end
|
data/lib/screen_tracker.rb
CHANGED
@@ -100,8 +100,6 @@ class ScreenTracker
|
|
100
100
|
|
101
101
|
# split out for unit testing purposes
|
102
102
|
def identify_digit bitmap
|
103
|
-
require 'ruby-debug'
|
104
|
-
# debugger
|
105
103
|
OCR.identify_digit(bitmap, @digits)
|
106
104
|
end
|
107
105
|
|
@@ -123,7 +121,7 @@ class ScreenTracker
|
|
123
121
|
@a ||= 1
|
124
122
|
@a += 1
|
125
123
|
p 'unable to identify digit!' + type.to_s + @a.to_s
|
126
|
-
File.binwrite("bad_digit#{@a}.bmp", digits[type])
|
124
|
+
File.binwrite("bad_digit#{@a}#{type}.bmp", digits[type])
|
127
125
|
end
|
128
126
|
# early return
|
129
127
|
return
|
File without changes
|
Binary file
|
Binary file
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|