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
data/FAQ
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
FAQ
|
2
|
+
|
3
|
+
Q. How can I easily watch this on my TV, not on my computer, silly!
|
4
|
+
|
5
|
+
A. Currently you'll either need to attach your computer to your TV (buy some long cables, or a new graphics card
|
6
|
+
or an adapter cable and some long cords, or get a laptop somehow (ex: buy a used older one) and plug that into your TV.
|
7
|
+
|
8
|
+
There is also some work working toward getting the stuff playing on your computer to stream live to your wii/ps3/xbox:
|
9
|
+
http://betterlogic.com/roger/?p=3023 has the beginnings of said work, though it doesn't work yet, as I have no demo hardware to
|
10
|
+
test it out with.
|
11
|
+
|
12
|
+
A history of thoughts leading up to this can be found here: http://betterlogic.com/roger/?p=2618
|
data/LICENSE
ADDED
data/README
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
This projects aims to allow users to "skip scenes" on media playback. It aims to be be an EDL (http://en.wikipedia.org/wiki/Edit_decision_list) player for any arbitrary player.
|
2
|
+
|
3
|
+
(VLC and online players, for example hulu/netflix).
|
4
|
+
|
5
|
+
Trouble Shooting:
|
6
|
+
|
7
|
+
If you have poor performance, possibly set the process priority to low on the DVD player program. Also report back.
|
data/Rakefile
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'jeweler'
|
2
|
+
require 'os'
|
3
|
+
Jeweler::Tasks.new do |s|
|
4
|
+
s.name = "sensible-cinema"
|
5
|
+
s.summary = "an EDL scene-selector/bleeper that works with online players like hulu"
|
6
|
+
s.email = "rogerdpack@gmail.com"
|
7
|
+
s.homepage = "http://github.com/rdp"
|
8
|
+
s.authors = ["Roger Pack"]
|
9
|
+
s.add_development_dependency 'rspec' # prefer rspec 2 I guess...
|
10
|
+
s.add_development_dependency 'jeweler'
|
11
|
+
s.add_development_dependency 'rdp-rmagick'
|
12
|
+
s.add_dependency 'mini_magick' # ocr
|
13
|
+
s.add_development_dependency 'hitimes' # now jruby compat. yea!
|
14
|
+
s.add_dependency 'sane', '>= 0.22.0'
|
15
|
+
s.add_dependency 'rdp-win32screenshot', '>= 0.0.6.2'
|
16
|
+
s.extensions = ["ext/mkrf_conf.rb"]
|
17
|
+
end
|
18
|
+
|
19
|
+
desc 'run all specs'
|
20
|
+
task 'spec' do
|
21
|
+
success = true
|
22
|
+
for file in Dir['spec/*spec*.rb'] do
|
23
|
+
p file
|
24
|
+
if !system('cd spec & ' + OS.ruby_bin + " ../" + file)
|
25
|
+
success = false
|
26
|
+
break
|
27
|
+
end
|
28
|
+
end
|
29
|
+
p 'all specs passed!' if success
|
30
|
+
end
|
data/TODO
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
== medium ==
|
2
|
+
|
3
|
+
make work with VLC and hulu with hours...
|
4
|
+
|
5
|
+
== low but actually want to do eventually (me) low prio: just do these...==
|
6
|
+
|
7
|
+
release ruby-y-y why not, it's interesting
|
8
|
+
release it "Linux compat anyone?"
|
9
|
+
|
10
|
+
just local files for my own edits...
|
11
|
+
|
12
|
+
== raw backlog ... based on user request.. ==
|
13
|
+
|
14
|
+
netflix
|
15
|
+
|
16
|
+
add my own stuff to imdb...
|
17
|
+
|
18
|
+
imdb parser
|
19
|
+
|
20
|
+
make it into a real live full functional app...like fully fully functional and good (for use, not editing), mostly with the drop down lists uh guess.
|
21
|
+
|
22
|
+
GUI: paste edit list, choose player
|
23
|
+
|
24
|
+
PISH
|
25
|
+
|
26
|
+
can overlay with a "fuzzer-outer" for specific coordinates somehow or other...
|
27
|
+
|
28
|
+
advertise like to lay men
|
29
|
+
|
30
|
+
with VLC non full screen, it does the annoying mouse thing needlessly.
|
31
|
+
|
32
|
+
hire out scene lists
|
33
|
+
|
34
|
+
youtube non full screened...hmmm
|
35
|
+
|
36
|
+
bleeper name
|
37
|
+
|
38
|
+
yank old gem versions (?) :)
|
39
|
+
|
40
|
+
overlay with wav file (would work for VLC, could also "click to mute" for the others...)
|
41
|
+
|
42
|
+
fix pending tests...
|
43
|
+
|
44
|
+
can black out certain coords to keep things pretty...
|
45
|
+
|
46
|
+
allow x2,y2 for player descriptions...
|
47
|
+
|
48
|
+
Linux port (call that good enough for usability on TV's...) between that and a VLC version...
|
49
|
+
|
50
|
+
a web runnable? Why not?
|
51
|
+
click here to watch your favorite film edited!
|
52
|
+
|
53
|
+
blank out with a user specifiable color (?)
|
54
|
+
|
55
|
+
Auto mute commercials?
|
56
|
+
|
57
|
+
rruby.net rubyy.net
|
58
|
+
|
59
|
+
new github username
|
60
|
+
|
61
|
+
replay parts
|
62
|
+
|
63
|
+
overlay/replace with some url of audio or video
|
64
|
+
|
65
|
+
control volume programmatically (using mouse) on the player itself.
|
66
|
+
control mute programmatically (using mouse) on the player itself.
|
67
|
+
|
68
|
+
overlay alpha transparent pic
|
69
|
+
|
70
|
+
Have a "list of all known movies (url's)" and be able to open (IE et al) to the correct part, and start playing them, and they work...
|
71
|
+
|
72
|
+
magnify video parts (?)
|
73
|
+
overlay with transparent gif?
|
74
|
+
|
75
|
+
OCR
|
76
|
+
pop it up only every so often (?)
|
77
|
+
after commercials?
|
78
|
+
|
79
|
+
user customizable levels...
|
80
|
+
maybe even "I don't like ones that are x, y, z", or "boring level x"
|
81
|
+
|
82
|
+
user-assignable "confidence" (how much time to 'wrap' surround the mutes, etc. to accomodate for slow computers/laggy internet/different players/poor input)
|
83
|
+
|
84
|
+
auto-assignment of EDL's to media:
|
85
|
+
DVD's
|
86
|
+
VLC
|
87
|
+
directory of scene-lists
|
88
|
+
web plugin?
|
89
|
+
|
90
|
+
Programmatically do all of the above, by driving a player with its real API.
|
91
|
+
VLC
|
92
|
+
Allow it to make mp4's somewhere.
|
93
|
+
See if burnable to DVD.
|
94
|
+
web interface?
|
95
|
+
auto start on DVD insertion (?)
|
96
|
+
and show appropriate scene-lists available based on title/md5 of something?
|
97
|
+
|
98
|
+
could have an easy
|
99
|
+
|
100
|
+
never do unless paid:
|
101
|
+
|
102
|
+
super easy streamer windows -> {XBOX360, wii, etc..} basically like playon, which appears to have no free equivalent, I guess, though you can
|
103
|
+
save the files somewhere and stream them (and stream DVD's [?]) using tversity...maybe some other things...hmm...but no netflix!
|
104
|
+
so currently they basically need to run a cable from laptop to PC, for me. windows laptop, for netflix, though a dedicated box could run things like boxee.
|
105
|
+
so I could create something that's basically windows -> ??? (ushare).
|
106
|
+
For now it's either a cable, a computer (with its cable), or pay.
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.6.0
|
data/bin/bad_digit10.bmp
ADDED
Binary file
|
data/bin/bad_digit11.bmp
ADDED
Binary file
|
data/bin/bad_digit12.bmp
ADDED
Binary file
|
data/bin/bad_digit13.bmp
ADDED
Binary file
|
data/bin/bad_digit14.bmp
ADDED
Binary file
|
data/bin/bad_digit15.bmp
ADDED
Binary file
|
data/bin/bad_digit16.bmp
ADDED
Binary file
|
data/bin/bad_digit17.bmp
ADDED
Binary file
|
data/bin/bad_digit18.bmp
ADDED
Binary file
|
data/bin/bad_digit19.bmp
ADDED
Binary file
|
data/bin/bad_digit2.bmp
ADDED
Binary file
|
data/bin/bad_digit20.bmp
ADDED
Binary file
|
data/bin/bad_digit21.bmp
ADDED
Binary file
|
data/bin/bad_digit22.bmp
ADDED
Binary file
|
data/bin/bad_digit3.bmp
ADDED
Binary file
|
data/bin/bad_digit4.bmp
ADDED
Binary file
|
data/bin/bad_digit5.bmp
ADDED
Binary file
|
data/bin/bad_digit6.bmp
ADDED
Binary file
|
data/bin/bad_digit7.bmp
ADDED
Binary file
|
data/bin/bad_digit8.bmp
ADDED
Binary file
|
data/bin/bad_digit9.bmp
ADDED
Binary file
|
data/bin/hours.bmp
ADDED
Binary file
|
data/bin/minute_ones.bmp
ADDED
Binary file
|
data/bin/minute_tens.bmp
ADDED
Binary file
|
data/bin/scene-skipper
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'sane'
|
3
|
+
Thread.abort_on_exception=true
|
4
|
+
for file in ['overlayer', 'keyboard_input', 'screen_tracker', 'mouse']
|
5
|
+
require_relative '../lib/' + file
|
6
|
+
end
|
7
|
+
|
8
|
+
$VERBOSE = 1 if ARGV.delete('-v')
|
9
|
+
$TEST = 1 if ARGV.delete('-t')
|
10
|
+
|
11
|
+
$stderr.puts 'warning: windows only for crucial parts currently' unless ENV['OS'] == 'Windows_NT'
|
12
|
+
|
13
|
+
first = ARGV[0]
|
14
|
+
|
15
|
+
if ARGV.length >= 1 && (File.exist?(first) || first == 'test')
|
16
|
+
|
17
|
+
if File.exist? first
|
18
|
+
overlay = OverLayer.new(first, ARGV[2])
|
19
|
+
overlay.start_thread true
|
20
|
+
else
|
21
|
+
puts 'warning--only doing screen dump in 4s...'
|
22
|
+
overlay = nil
|
23
|
+
$VERBOSE = 1 # that's what they wanted...
|
24
|
+
sleep 4
|
25
|
+
end
|
26
|
+
|
27
|
+
if ARGV[1] && File.exist?(ARGV[1])
|
28
|
+
# this one doesn't use file updates, so pass it the string
|
29
|
+
screen_tracker = ScreenTracker.new_from_yaml File.binread(ARGV[1]), overlay
|
30
|
+
screen_tracker.dump_bmp if $VERBOSE
|
31
|
+
exit 1 unless overlay
|
32
|
+
screen_tracker.process_forever_in_thread
|
33
|
+
Mouse.jitter_forever_in_own_thread
|
34
|
+
else
|
35
|
+
puts 'warning--not using any screen tracking...'
|
36
|
+
end
|
37
|
+
|
38
|
+
key_input = KeyboardInput.new overlay
|
39
|
+
key_input.start_thread # status thread
|
40
|
+
key_input.handle_keystrokes_forever # when this method exits, we want to exit fully...
|
41
|
+
|
42
|
+
else
|
43
|
+
puts <<-END
|
44
|
+
|
45
|
+
syntax: mute_lists.yml [player_description.yml] [-v (verbose [chatty] mode)] [-t (test mode)]
|
46
|
+
See the #{File.expand_path(File.dirname(__FILE__), "..")}/zamples for more info on creating files.
|
47
|
+
END
|
48
|
+
|
49
|
+
for file in Dir[__dir__ + '../zamples/mute*/*']
|
50
|
+
puts "\n", "Example file:", file + "\n\n", File.read(file)
|
51
|
+
end
|
52
|
+
|
53
|
+
puts '', 'Available files:'
|
54
|
+
for file in Dir[__dir__ + '../zamples/*/*']
|
55
|
+
puts File.expand_path(file) unless File.directory?(file)
|
56
|
+
end
|
57
|
+
exit 1
|
58
|
+
end
|
data/bin/second_ones.bmp
ADDED
Binary file
|
data/bin/second_tens.bmp
ADDED
Binary file
|
data/ext/mkrf_conf.rb
ADDED
data/lib/blanker.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
class Blanker
|
4
|
+
|
5
|
+
if RUBY_PLATFORM =~ /java/
|
6
|
+
require 'java'
|
7
|
+
JFrame = javax.swing.JFrame
|
8
|
+
JPanel = javax.swing.JPanel
|
9
|
+
|
10
|
+
def self.blank_full_screen!
|
11
|
+
# a new screen each time as other jruby doesn't terminate as gracefully as we would like...
|
12
|
+
frame = JFrame.new("Edited!") # ltodo take out...
|
13
|
+
frame.default_close_operation = JFrame::EXIT_ON_CLOSE
|
14
|
+
frame.set_location(0,0)
|
15
|
+
frame.set_size(2000, 2000) # ltodo better coords...
|
16
|
+
frame.show
|
17
|
+
# lodo on top?
|
18
|
+
|
19
|
+
fr = frame
|
20
|
+
fr.set_resizable(false)
|
21
|
+
|
22
|
+
fr.set_undecorated(true) unless fr.is_displayable
|
23
|
+
|
24
|
+
# probably unnecessary
|
25
|
+
panel = JPanel.new
|
26
|
+
frame.add(panel)
|
27
|
+
# frame.set_background()
|
28
|
+
panel.repaint
|
29
|
+
panel.revalidate
|
30
|
+
# too heavy!
|
31
|
+
# gd = java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice()
|
32
|
+
# gd.set_full_screen_window(fr)
|
33
|
+
@fr = fr
|
34
|
+
@fr.set_visible(true)
|
35
|
+
end
|
36
|
+
else
|
37
|
+
|
38
|
+
def self.blank_full_screen!
|
39
|
+
puts 'the screen is now...blank!'
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.unblank_full_screen!
|
45
|
+
if RUBY_PLATFORM =~ /java/
|
46
|
+
if @fr
|
47
|
+
@fr.dispose
|
48
|
+
end
|
49
|
+
else
|
50
|
+
puts 'the screen is now...visible!'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'sane'
|
3
|
+
require 'Win32API'
|
4
|
+
|
5
|
+
# does the jruby check inline
|
6
|
+
|
7
|
+
class KeyboardInput
|
8
|
+
|
9
|
+
def initialize fella
|
10
|
+
@fella = fella
|
11
|
+
end
|
12
|
+
|
13
|
+
def start_thread
|
14
|
+
Thread.new { loop {
|
15
|
+
print get_line_printout
|
16
|
+
sleep 0.1
|
17
|
+
} }
|
18
|
+
end
|
19
|
+
|
20
|
+
def get_line_printout
|
21
|
+
status = @fella.status
|
22
|
+
# scary hard coded values here...
|
23
|
+
" " * 20 + "\b"*150 + status
|
24
|
+
end
|
25
|
+
|
26
|
+
def getch
|
27
|
+
@getch ||= Win32API.new('crtdll', '_getch', [], 'L')
|
28
|
+
@getch.call
|
29
|
+
end
|
30
|
+
|
31
|
+
def handle_keystrokes_forever
|
32
|
+
raise 'only jruby supported, as it looks just too messy in normal ruby' unless OS.java?
|
33
|
+
while(ch = getch)
|
34
|
+
return if ch.in? [3, 113] # ctrl+c, q -> exit
|
35
|
+
# lodo handle arrow keys, too, which is a bit more complicated...
|
36
|
+
handle_keystroke ch
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def handle_keystroke ch
|
41
|
+
string = "" << ch
|
42
|
+
@fella.keyboard_input(string)
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
data/lib/mouse.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'ffi'
|
3
|
+
|
4
|
+
module Mouse
|
5
|
+
extend FFI::Library
|
6
|
+
|
7
|
+
ffi_lib 'user32'
|
8
|
+
ffi_convention :stdcall
|
9
|
+
|
10
|
+
MOUSEEVENTF_MOVE = 1
|
11
|
+
INPUT_MOUSE = 0
|
12
|
+
MOUSEEVENTF_ABSOLUTE = 0x8000
|
13
|
+
|
14
|
+
class MouseInput < FFI::Struct
|
15
|
+
layout :dx, :long,
|
16
|
+
:dy, :long,
|
17
|
+
:mouse_data, :ulong,
|
18
|
+
:flags, :ulong,
|
19
|
+
:time, :ulong,
|
20
|
+
:extra, :ulong
|
21
|
+
end
|
22
|
+
class InputEvent < FFI::Union
|
23
|
+
layout :mi, MouseInput
|
24
|
+
end
|
25
|
+
class Input < FFI::Struct
|
26
|
+
layout :type, :ulong,
|
27
|
+
:evt, InputEvent
|
28
|
+
end
|
29
|
+
|
30
|
+
# UINT SendInput(UINT nInputs, LPINPUT pInputs, int cbSize);
|
31
|
+
attach_function :SendInput, [ :uint, :pointer, :int ], :uint
|
32
|
+
|
33
|
+
def self.jitter_forever_in_own_thread
|
34
|
+
|
35
|
+
myinput = Mouse::Input.new
|
36
|
+
myinput[:type] = Mouse::INPUT_MOUSE
|
37
|
+
|
38
|
+
in_evt = myinput[:evt][:mi]
|
39
|
+
|
40
|
+
in_evt[:mouse_data] = 0
|
41
|
+
in_evt[:flags] = Mouse::MOUSEEVENTF_MOVE # | Mouse::MOUSEEVENTF_ABSOLUTE
|
42
|
+
in_evt[:time] = 0
|
43
|
+
in_evt[:extra] = 0
|
44
|
+
in_evt[:dx] = 0
|
45
|
+
in_evt[:dy] = 8 # just enough for VLC full screen...
|
46
|
+
|
47
|
+
Thread.new {
|
48
|
+
loop {
|
49
|
+
in_evt[:dy] *= -1
|
50
|
+
Mouse.SendInput(1, myinput, Mouse::Input.size)
|
51
|
+
in_evt[:dy] *= -1
|
52
|
+
sleep 0.05
|
53
|
+
Mouse.SendInput(1, myinput, Mouse::Input.size)
|
54
|
+
sleep 0.75
|
55
|
+
}
|
56
|
+
}
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
data/lib/muter.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'rubygems' # ugh
|
2
|
+
require 'ffi'
|
3
|
+
|
4
|
+
module Muter
|
5
|
+
# from msdn on keybd_event ...
|
6
|
+
|
7
|
+
VK_VOLUME_DOWN = 0xAE
|
8
|
+
VK_VOLUME_UP = 0xAF
|
9
|
+
VK_VOLUME_MUTE = 0xAD
|
10
|
+
KEYEVENTF_KEYUP = 2
|
11
|
+
|
12
|
+
extend FFI::Library
|
13
|
+
ffi_lib 'user32'
|
14
|
+
ffi_convention :stdcall
|
15
|
+
|
16
|
+
attach_function :keybd_event, [ :uchar, :uchar, :int, :pointer ], :void
|
17
|
+
|
18
|
+
def hit_mute_key
|
19
|
+
# simulate pressing the mute key
|
20
|
+
keybd_event(VK_VOLUME_MUTE, 0, 0, nil)
|
21
|
+
keybd_event(VK_VOLUME_MUTE, 0, KEYEVENTF_KEYUP, nil)
|
22
|
+
end
|
23
|
+
|
24
|
+
def hit_volume_up_key
|
25
|
+
keybd_event(VK_VOLUME_UP, 0, 0, nil)
|
26
|
+
keybd_event(VK_VOLUME_UP, 0, KEYEVENTF_KEYUP, nil)
|
27
|
+
end
|
28
|
+
|
29
|
+
def hit_volume_down_key
|
30
|
+
keybd_event(VK_VOLUME_DOWN, 0, 0, nil)
|
31
|
+
keybd_event(VK_VOLUME_DOWN, 0, KEYEVENTF_KEYUP, nil)
|
32
|
+
end
|
33
|
+
|
34
|
+
def mute!
|
35
|
+
#unmute! # just in case
|
36
|
+
hit_mute_key
|
37
|
+
end
|
38
|
+
# TODO better for 7...
|
39
|
+
def unmute!
|
40
|
+
hit_mute_key # Windows XP...
|
41
|
+
hit_volume_down_key
|
42
|
+
hit_volume_up_key
|
43
|
+
end
|
44
|
+
|
45
|
+
# allow for Muter.xxx
|
46
|
+
extend self
|
47
|
+
|
48
|
+
end
|
data/lib/ocr.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'mini_magick'
|
2
|
+
require 'open3'
|
3
|
+
|
4
|
+
# helper for OCR'ing single digits that were screen captured
|
5
|
+
module OCR
|
6
|
+
|
7
|
+
GOCR = File.expand_path(File.dirname(__FILE__) + "/../vendor/gocr048.exe -C 0-9:/ ")
|
8
|
+
|
9
|
+
CACHE = {}
|
10
|
+
|
11
|
+
# options are :might_be_colon, :should_invert
|
12
|
+
def identify_digit memory_bitmap, options = {}
|
13
|
+
if CACHE[memory_bitmap]
|
14
|
+
print 'h' if $DEBUG
|
15
|
+
return CACHE[memory_bitmap]
|
16
|
+
else
|
17
|
+
p 'ocr cache miss' if $DEBUG
|
18
|
+
end
|
19
|
+
might_be_colon = options[:might_be_colon]
|
20
|
+
should_invert = options[:should_invert]
|
21
|
+
if might_be_colon
|
22
|
+
# do processing in-line <sigh>
|
23
|
+
total = (memory_bitmap.scan /\x00{5}+/).length
|
24
|
+
if total >= 3 # really should be 4 for VLC
|
25
|
+
# it had some dots...must have been a colon!
|
26
|
+
end
|
27
|
+
CACHE[memory_bitmap] = ":"
|
28
|
+
return ":"
|
29
|
+
end
|
30
|
+
image = MiniMagick::Image.from_blob(memory_bitmap)
|
31
|
+
image.format(:pnm) # expensive, requires convert.exe in path...
|
32
|
+
if should_invert # mogrify calls it negate...
|
33
|
+
image.negate
|
34
|
+
end
|
35
|
+
for level in [130, 100] # 100 for hulu...
|
36
|
+
input, output, error, thread_if_on_19 = Open3.popen3 GOCR + " -l #{level} -"
|
37
|
+
input.write image.to_blob
|
38
|
+
input.close
|
39
|
+
a = output.read
|
40
|
+
output.close
|
41
|
+
a.strip!
|
42
|
+
if a =~ /[0-9]/
|
43
|
+
a = a.to_i
|
44
|
+
CACHE[memory_bitmap] = a
|
45
|
+
return a
|
46
|
+
end
|
47
|
+
end
|
48
|
+
nil
|
49
|
+
end
|
50
|
+
|
51
|
+
def version
|
52
|
+
`#{GOCR} -h 2>&1`
|
53
|
+
end
|
54
|
+
|
55
|
+
extend self
|
56
|
+
|
57
|
+
end
|