sensible-cinema 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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
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
@@ -0,0 +1,5 @@
1
+ All files released under the GPLv3 license [1] unless otherwise specified. Ping me if you want this changed.
2
+
3
+ May contains 3rd party libraries under their own license.
4
+
5
+ [1] http://www.gnu.org/licenses/gpl.html
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
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
data/bin/hours.bmp ADDED
Binary file
Binary file
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
Binary file
Binary file
data/ext/mkrf_conf.rb ADDED
@@ -0,0 +1,5 @@
1
+ raise 'must be using jruby to be able to run this...at least for now' unless RUBY_PLATFORM =~ /java/
2
+
3
+ f = File.open(File.join(File.dirname(__FILE__), "Rakefile"), "w") # create dummy rakefile to indicate success
4
+ f.write("task :default\n")
5
+ f.close
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