sensible-cinema 0.7.7 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/README +14 -11
  2. data/TODO +33 -38
  3. data/VERSION +1 -1
  4. data/bin/sensible-cinema +30 -14
  5. data/ext/mkrf_conf.rb +3 -2
  6. data/lib/blanker.rb +42 -46
  7. data/lib/fake_blanker.rb +18 -0
  8. data/lib/file_chooser.rb +2 -2
  9. data/lib/ocr.rb +37 -10
  10. data/lib/overlayer.rb +12 -11
  11. data/lib/screen_tracker.rb +55 -39
  12. data/spec/blanker.spec.rb +12 -4
  13. data/spec/images/youtube_0.bmp +0 -0
  14. data/spec/images/youtube_1.bmp +0 -0
  15. data/spec/images/youtube_2_0.bmp +0 -0
  16. data/spec/images/youtube_2_5.bmp +0 -0
  17. data/spec/images/youtube_2_6.bmp +0 -0
  18. data/spec/images/youtube_3_0.bmp +0 -0
  19. data/spec/images/youtube_4.bmp +0 -0
  20. data/spec/images/youtube_4_0.bmp +0 -0
  21. data/spec/images/youtube_5.bmp +0 -0
  22. data/spec/images/youtube_6.bmp +0 -0
  23. data/spec/images/youtube_small_0.bmp +0 -0
  24. data/spec/images/youtube_small_2.bmp +0 -0
  25. data/spec/images/youtube_small_2_0.bmp +0 -0
  26. data/spec/images/youtube_small_4.bmp +0 -0
  27. data/spec/ocr.spec.rb +63 -11
  28. data/spec/overlayer.spec.rb +4 -2
  29. data/spec/screen_tracker.spec.rb +3 -4
  30. data/zamples/players/{total_length_over_an_hour/hulu_full_screened.yml → hulu/total_length_over_an_hour.yml} +0 -0
  31. data/zamples/players/{total_length_over_an_hour/vlc_full_screened.yml → vlc/full_screened_total_length_over_an_hour.yml} +0 -0
  32. data/zamples/players/{total_length_under_an_hour/vlc_non_full_screened.yml → vlc/non_full_screened_total_length_under_an_hour.yml} +0 -0
  33. data/zamples/players/{total_length_over_an_hour/vlc_windowed.yml → vlc/vlc_windows_total_length_over_an_hour.yml} +0 -0
  34. data/zamples/players/youtube/full_screened_1024x768.yml +17 -0
  35. data/zamples/players/youtube/full_screened_1152x864.yml +17 -0
  36. data/zamples/players/youtube/full_screened_1680x1050.yml +17 -0
  37. data/zamples/players/youtube/note_these_assume_less_than_10_minutes_length.txt +0 -0
  38. data/zamples/scene_lists/categories.yml b/data/zamples/scene_lists/category → descriptions.yml +0 -0
  39. data/zamples/scene_lists/gummy_bear_song_youtube.yml +8 -0
  40. data/zamples/scene_lists/nuki_song_youtube.yml +9 -0
  41. metadata +30 -12
  42. data/spec/open.bat +0 -1
  43. data/zamples/players/sample_snapshots/utube.JPG +0 -0
  44. data/zamples/players/sample_snapshots/youtube full screen big screen.jpg +0 -0
data/README CHANGED
@@ -1,14 +1,15 @@
1
1
  Sensible-cinema is a program that allows you to do pre-programmed scene selection (i.e. "mute out"
2
2
  or "bleep out" scenes) on arbitrary media players like netflix online, vlc, etc.
3
3
 
4
- Currently it takes as input a list of known "skip-worthy" scenes.
4
+
5
+ Currently it takes as input a list of "skippable" scenes, and a player description.
5
6
  It then tracks whichever player you are using, and mutes or blanks out the system appropriately,
6
7
  during the scenes specified.
7
8
 
8
9
  It works out of the box with the hulu and VLC players on windows. It isn't hard to
9
10
  add new players, and probably wouldn't be too hard to add more operating systems.
10
11
 
11
- == How to use ==
12
+ == How to Use ==
12
13
 
13
14
  Start playing your movie in its respective player, then startup sensible-cinema from
14
15
  the command line thus:
@@ -66,11 +67,11 @@ To create it, basically you notice something you want to add to the list, add it
66
67
  in your media player, and it should now be muted/blanked out automatically.
67
68
 
68
69
  So here is a way to create your scene descriptions file.
69
- First create a new file [2], and select it in sensible-cinema (even though it's still blank).
70
- Now use sensible-cinema and select the new file you just created.
71
- Now "preview" the movie, and as you do, you're going scenes to the file, and then test your additions.
72
- As you watch and hit a questionable scene, go back to several seconds before it using your player's
73
- controls. When you encounter the scene again, track its beginning and ending time. One way to do this
70
+ First create a new file [2], and now select it for use in sensible-cinema (even though it's still blank).
71
+ Now "preview" your movie. As you do, you're going to add scenes to that file, and then test your additions.
72
+
73
+ So as you watch when you encounter a questionable scene, go back several seconds using your player's
74
+ controls. When you encounter it again, track its beginning and ending time. One way to do this
74
75
  is to, just before and just after the scene, hit the space bar *in the sensible-cinema window*.
75
76
  Hitting the space bar outputs the current time. If you hit it twice, once before and once after,
76
77
  you should now have two reasonably accurate "timestamps" displayed.
@@ -82,9 +83,11 @@ Once you're done then you can contribute your scene descriptions file if desired
82
83
 
83
84
  [1] http://github.com/rdp/sensible-cinema/issues
84
85
  [2] The easiest way to do this is to start sensible-cinema, then instead of choosing an existing file,
85
- right click and choose "New -> Text Document" Now rename it (leaving it as .txt).
86
- "Right click -> Open" to open it in an editor. Now also select that same file in sensible-cinema.
87
- Another easy way is to "right drag" an existing file then rename it and edit that one.
86
+ "right click" on the existing file "example_scene_list.yml" and choose "Copy"
87
+ now right click below the list of files and choose "paste"
88
+ This will create the file "example_scene_list Copy.yml"
89
+ Right click on it, choose rename, and give it a better name.
90
+ Now "right click -> Open" to open it in an editor (recommend installing notepad++ and using that).
88
91
 
89
92
  == FAQ ==
90
93
 
@@ -96,7 +99,7 @@ A. Not yet. And maybe. Currently you'll either need to attach your computer to
96
99
  could run an ethernet cable from your computer, as well [1].
97
100
  I'd be happy to do a linux port of sensible-cinema if anybody requests it for their dedicated TV computer.
98
101
  There has also been some work toward getting your computer to stream "live" to your wii/ps3/xbox.
99
- github message me if you're interested in trying it out!
102
+ github message me if you're interested in trying it out (testers wanted)!
100
103
 
101
104
  Q. What movies does this work with?
102
105
 
data/TODO CHANGED
@@ -2,46 +2,43 @@
2
2
 
3
3
  == low but actually want to do eventually (me) low prio: just do these...==
4
4
 
5
- release ruby-y-y why not, it's interesting
6
- "Linux compat anyone?"
7
- utube nuki (somewhere with a real sound card...which would be the home comp)
8
5
  generations the first profanidade...
9
-
10
- == random backlog ... based on user request..remember: just local files for my own needs...==
11
6
 
12
- just plow forward, to "grab" available ideas...
7
+ == random backlog ... based on user request..remember: just local files for my own needs...==
8
+ note: just plow forward, to "grab" available ideas...
9
+ except that for now, just what *I* plan on needing for myself.
13
10
 
14
- make it "quieter" at certain parts, arbitrarily...
11
+ refactor: "screen time change", order should be swapped in bin/x
15
12
 
16
- release a zip file that they can just click on something to run it...self-extractor yeah.
13
+ auto-play on youtube when it comes up...hmm... (detect)
17
14
 
18
- snag the close captioning for a profanity filter?
15
+ able to make it "quieter" at certain parts, arbitrarily...
19
16
 
20
- make it able to use multiple players so I can maximize VLC...
17
+ easier installer for windows: release a zip file that they can just click on a .bat file to run it
18
+ later: it installs/uninstalls appropo
19
+ suggestion: self-extractor
21
20
 
22
- blank overlay "and you are one awesome klingon"
21
+ snag the close captioning as a profanity filter?
23
22
 
24
- screencast of something helpful (use, creation).
23
+ make it able to use multiple players so I can maximize VLC...
25
24
 
26
- optimize (tell them) imdb: http://www.imdb.com/board/bd0000042/thread/58361958?d=58361958, english friendlier url's
25
+ blank overlay text like "and you are one awesome klingon"
27
26
 
28
- bundle fewer imagemagick binaries
27
+ screencast of things helpful (use, creation).
29
28
 
30
29
  TSR that monitors "oh you're opening a VLC? you're playing the E drive? That's bob's big plan? You're maximized? Full screened? watching x on hulu?"
31
30
 
32
- netflix player
31
+ a netflix online player description
33
32
 
34
- add my own stuff to imdb...
35
- antz to imdb...
33
+ add my stuff to imdb...
36
34
 
37
- imdb parser...somehow
35
+ an imdb parser?
38
36
 
39
- 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.
37
+ user customizable levels...
38
+ maybe even "I don't like ones that are x, y, z", or "boring level x"
40
39
 
41
40
  make a redcar installer for their use...
42
41
 
43
- PISH
44
-
45
42
  can overlay with a "fuzzer-outer" for specific coordinates somehow or other...
46
43
 
47
44
  advertise like to lay men, to try to popularize
@@ -54,16 +51,17 @@ overlay with wav file (would work for VLC, could also "click to mute" for the ot
54
51
 
55
52
  fix any pending tests...
56
53
 
57
- can black out certain coords to keep things pretty...
54
+ can black out certain coords to keep things prettier...
58
55
 
59
56
  allow x2,y2 for player descriptions...
60
57
 
61
58
  Linux port (call that good enough for usability on TV's...) between that and a VLC version...
62
59
 
63
60
  a web runnable? Why not?
64
- click here to watch your favorite film edited!
61
+ click here to watch your favorite film edited! Just click!
65
62
 
66
- blank out with a user specifiable color (?)
63
+ blank out with specifiable color
64
+ better default color?
67
65
 
68
66
  Auto mute/blank commercials?
69
67
 
@@ -78,37 +76,34 @@ control volume programmatically (using mouse) on the player itself.
78
76
  control mute programmatically (using mouse) on the player itself.
79
77
  control location programmatically (using mouse) on the player itself.
80
78
 
81
- compare labyrinth timings with a real DVD player...
79
+ compare timings with a real DVD player...
82
80
 
83
- overlay with alpha transparent pic
81
+ overlay with an alpha transparent pic
84
82
 
85
83
  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...
86
84
 
87
- magnify video parts (?)
88
-
89
- user customizable levels...
90
- maybe even "I don't like ones that are x, y, z", or "boring level x"
91
-
92
85
  user-assignable "confidence" (how much time to 'wrap' surround the mutes, etc. to accomodate for slow computers/laggy internet/different players/poor input)
93
86
 
94
-
87
+ does my sweet heart have any suggestions?
95
88
 
96
89
  auto-assignment of EDL's to media:
97
- DVD's (right click...)
90
+ DVD's (right click on DVD player, play with scene-skipper?)
98
91
  web browser plugin?
99
92
  auto start on DVD insertion (?)
100
93
  and show appropriate scene-lists available based on title/md5 of something?
101
94
 
102
95
  Programmatically do all of the above, by driving a player with its real API.
103
96
  VLC
104
- Allow it to record to mp4's somewhere.
105
- See if burnable to DVD/CD ...
106
- (use web interface?)
97
+ Allow it to record to mp4's somewhere (recordable)
98
+ burnable to DVD/CD ...
99
+ (use VLC's web interface?)
107
100
 
108
- never do unless paid:
101
+ use spiffy differentiation for DVD's on windows
109
102
 
110
103
  super easy streamer windows -> {XBOX360, wii, etc..} basically like playon, which appears to have no free equivalent, I guess, though you can
111
104
  save the files somewhere and stream them (and stream DVD's [?]) using tversity...maybe some other things...hmm...but no netflix!
112
105
  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.
113
106
  so I could create something that's basically windows -> ??? (ushare).
114
- For now it's either a cable, a computer (with its cable), or pay.
107
+ For now it's either a cable, a computer (with its cable), or pay.
108
+ todo: make a VLC wrapper so it works *if your soundcard supports it*
109
+ after: make the same work awesome on doze 7 without soundcard support :)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.7.7
1
+ 0.9.3
data/bin/sensible-cinema CHANGED
@@ -1,3 +1,4 @@
1
+ puts 'Welcome to Sensible Cinema...'
1
2
  require 'rubygems'
2
3
  require 'sane'
3
4
 
@@ -36,43 +37,58 @@ else
36
37
  scene_list = ARGV.shift
37
38
 
38
39
  if scene_list == 'test'
39
- puts 'warning--only doing screen dump in 4s...'
40
40
  overlay = nil
41
- $VERBOSE = 1 # that's what they wanted...
42
- sleep 4
41
+ p 'got test...just doing screen dump'
42
+ $VERBOSE=true # some extra output
43
43
  else
44
44
  if !File.exist? scene_list.to_s
45
+ puts 'Select Scene Descriptions file'
45
46
  scene_list = FileChooser.choose_file("SELECT SCENE DESCRIPTIONS FILE", __dir__ + "/../zamples/scene_lists")
46
47
  end
48
+
47
49
  unless scene_list
48
- puts "error: have to specify a scene descriptions file\n or specify \"test\" on the command line if you just want to snapshot your player"
49
- exit 1
50
+ puts "error: have to specify a scene descriptions file\n or specify \"test\" on the command line if you just want to snapshot your player"
51
+ exit 1
50
52
  end
51
- puts 'Selected scene descriptions file ' + File.basename(scene_list) + " (#{scene_list})", ''
52
- overlay = OverLayer.new(scene_list)
53
+ puts 'Selected scene descriptions file ' + File.basename(scene_list) + "\n\t(#{scene_list})"
54
+ Blanker.startup
55
+
53
56
  end
54
57
 
55
58
  player_description = ARGV.shift.to_s
56
59
  if !File.exist?(player_description)
57
- player_description = FileChooser.choose_file("SELECT PLAYER (optional)", __dir__ + "/../zamples/players")
60
+ puts 'Please Select Computer Player'
61
+ player_description = FileChooser.choose_file("SELECT COMPUTER PLAYER", __dir__ + "/../zamples/players")
58
62
  end
59
63
 
64
+ # start it late as it has an annoying startup blip
65
+ overlay = OverLayer.new(scene_list)
66
+
60
67
  if File.exist? player_description.to_s
61
- # this one doesn't use file updates, so pass it the string
62
- Mouse.jitter_forever_in_own_thread
63
- puts 'Selected player ' + File.basename(player_description) + " (#{player_description})", ''
68
+ puts 'Selected player ' + File.basename(player_description) + "\n\t(#{player_description})"
69
+ # this one doesn't use any updates, so just pass in file contents, not filename
64
70
  screen_tracker = ScreenTracker.new_from_yaml File.binread(player_description), overlay
65
- screen_tracker.dump_bmp if $VERBOSE
71
+ Mouse.jitter_forever_in_own_thread # when this ends you know the snapshot was taken...
72
+
66
73
  # exit early if we just wanted a screen dump...a little kludgey...
67
- exit 1 unless overlay
74
+ unless overlay
75
+ puts 'warning--only doing screen dump in T-minus 4s...'
76
+ sleep 4
77
+ screen_tracker.dump_bmp
78
+ exit 1
79
+ end
68
80
  screen_tracker.process_forever_in_thread
69
81
  else
70
82
  puts 'warning--not using any screen tracking...'
71
83
  end
84
+ OCR.unserialize_cache_from_disk # do this every time so we don't delete it if they don't have one...
72
85
 
86
+ puts "Opening the curtains... (please play in player now)"
73
87
  overlay.start_thread true
74
88
  key_input = KeyboardInput.new overlay
75
89
  key_input.start_thread # status thread
76
90
  key_input.handle_keystrokes_forever # when this method exits, we want to exit fully...
77
-
91
+ Blanker.shutdown # lodo move this and the 'q' key to within overlayer
92
+ OCR.serialize_cache_to_disk
93
+
78
94
  end
data/ext/mkrf_conf.rb CHANGED
@@ -1,7 +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
-
3
+ # reset the OCR cache...
4
+ require File.dirname(__FILE__) + '/../lib/ocr'
5
+ OCR.clear_cache!
5
6
 
6
7
  f = File.open(File.join(File.dirname(__FILE__), "Rakefile"), "w") # create dummy rakefile to indicate success
7
8
  f.write("task :default\n")
data/lib/blanker.rb CHANGED
@@ -1,54 +1,50 @@
1
-
2
-
3
- class Blanker
1
+ if RUBY_PLATFORM !~ /java/
2
+ require_relative 'fake_blanker'
3
+ else
4
4
 
5
- if RUBY_PLATFORM =~ /java/
6
- require 'java'
7
- JFrame = javax.swing.JFrame
8
- JPanel = javax.swing.JPanel
5
+ require 'java'
9
6
 
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("blanked section") # ltodo pass in param
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
- # MRI fake blanker :)
38
- def self.blank_full_screen!
39
- puts 'the screen is now...blank!'
7
+ class Blanker
8
+ JFrame = javax.swing.JFrame
9
+ JLabel = javax.swing.JLabel
10
+
11
+ def self.startup
12
+ @fr = JFrame.new("blanked section")
13
+ @fr.default_close_operation = JFrame::EXIT_ON_CLOSE
14
+ @fr.set_size(2000, 2000) # ltodo better size coords ?
15
+
16
+ @label = JLabel.new(" Blank section")
17
+ @fr.add(@label)
18
+ @label.repaint
19
+ @label.revalidate
20
+
21
+ @fr.set_resizable(false)
22
+ @fr.set_visible(true) # have to do this once, to ever see the thing
23
+ # lodo does this really speed things up to pre-create it? that icon is a bit ugly...
24
+ unblank_full_screen! # and hide it to start
40
25
  end
41
-
42
- end
43
-
44
- def self.unblank_full_screen!
45
- if RUBY_PLATFORM =~ /java/
46
- if @fr
47
- @fr.dispose
26
+
27
+ def self.blank_full_screen! seconds
28
+ if seconds
29
+ @label.set_text " #{seconds} s"
30
+ else
31
+ @label.set_text " Blank section"
48
32
  end
49
- else
50
- puts 'the screen is now...visible!'
33
+ # somewhat hacky work around for doze: http://www.experts-exchange.com/Programming/Languages/Java/Q_22977145.html
34
+ @fr.setAlwaysOnTop(false)
35
+ @fr.setAlwaysOnTop(true)
36
+ @fr.set_location(0,0)
37
+ end
38
+
39
+ def self.unblank_full_screen!
40
+ # off screen...
41
+ @fr.set_location(-2100, -2100)
42
+ end
43
+
44
+ def self.shutdown
45
+ @fr.dispose
51
46
  end
47
+
52
48
  end
53
49
 
54
50
  end
@@ -0,0 +1,18 @@
1
+ puts 'warning--using fake blanker'
2
+
3
+ class Blanker
4
+
5
+ def self.startup
6
+ end
7
+ def self.shutdown
8
+ end
9
+
10
+ def self.blank_full_screen! text
11
+ puts 'the screen is now...blank!'
12
+ end
13
+
14
+ def self.unblank_full_screen!
15
+ puts 'the screen is now...visible!'
16
+ end
17
+
18
+ end
data/lib/file_chooser.rb CHANGED
@@ -13,10 +13,10 @@ module FileChooser
13
13
  fc.setDirectory(dir)
14
14
  end
15
15
  # lodo allow for a FileFilter, too...
16
- Thread.new { sleep 2; fc.to_front } # it gets hidden, unfortunately
16
+ Thread.new { sleep 2; fc.to_front } # it gets hidden, unfortunately, so try and bring it again to the front...
17
17
  fc.show
18
18
  if fc.get_file
19
- out = fc.get_directory + '\\' + fc.get_file
19
+ out = fc.get_directory + fc.get_file
20
20
  end
21
21
  fc.remove_notify # allow out app to exit
22
22
  out
data/lib/ocr.rb CHANGED
@@ -1,23 +1,23 @@
1
1
  im_path = File.expand_path(File.dirname(__FILE__) + "/../vendor/imagemagick") # convert.exe wants to only be chosen from here...
2
2
  ENV['PATH'] = im_path + ';' + ENV['PATH']
3
3
 
4
- require 'mini_magick'
5
-
6
4
  # helper for OCR'ing single digits that were screen captured
7
5
  module OCR
8
6
 
9
- GOCR = File.expand_path(File.dirname(__FILE__) + "/../vendor/gocr048.exe -C 0-9:/S ")
7
+ GOCR = File.expand_path(File.dirname(__FILE__) + "/../vendor/gocr048.exe -C 0-9:/ ")
10
8
 
11
9
  CACHE = {}
12
10
 
13
11
  # options are :might_be_colon, :should_invert
14
12
  def identify_digit memory_bitmap, options = {}
15
- if CACHE[memory_bitmap]
16
- return CACHE[memory_bitmap]
13
+ require 'mini_magick' # installation woe, but actually pretty fast
14
+
15
+ if CACHE.has_key?(memory_bitmap)
16
+ return CACHE[memory_bitmap] unless (defined?($OCR_NO_CACHE) && $OCR_NO_CACHE)
17
17
  end
18
18
  if options[:might_be_colon]
19
19
  # do processing in-line <sigh>
20
- total = (memory_bitmap.scan /\x00{5}+/).length
20
+ total = (memory_bitmap.scan(/\x00{5}+/)).length
21
21
  if total >= 3 # really should be 4 for VLC
22
22
  # it had some darkness...therefore have been a colon!
23
23
  CACHE[memory_bitmap] = ":"
@@ -25,21 +25,30 @@ module OCR
25
25
  end
26
26
  end
27
27
  image = MiniMagick::Image.from_blob(memory_bitmap)
28
- image.format(:pnm) # expensive, requires convert.exe in path...
28
+ # any operation on image is expensive, requires convert.exe in path...
29
29
  if options[:should_invert]
30
+ # hulu wants negate
31
+ # but doesn't want sharpen, for whatever reason...
30
32
  # mogrify calls it negate...
31
33
  image.negate
34
+ else
35
+ # youtube wants sharpen...
36
+ image.sharpen(2)
32
37
  end
33
- for level in [130, 100] # 100 for hulu...
38
+
39
+ image.format(:pnm)
40
+ for level in [130, 100, 0] # 130 for vlc, 100 for hulu, 0 for some youtube
34
41
  a = `#{GOCR} -l #{level} #{image.path} 2>NUL`
35
- a.strip!
36
- a = '3' if a == 'S' # sigh
42
+ # a can be like "_1_\n"
37
43
  if a =~ /[0-9]/
44
+ a.strip!
45
+ a.gsub!('_', '')
38
46
  a = a.to_i
39
47
  CACHE[memory_bitmap] = a
40
48
  return a
41
49
  end
42
50
  end
51
+ # don't cache it...could use up too much space on accident.
43
52
  nil
44
53
  end
45
54
 
@@ -47,6 +56,24 @@ module OCR
47
56
  `#{GOCR} -h 2>&1`
48
57
  end
49
58
 
59
+ def clear_cache!
60
+ CACHE.clear
61
+ File.delete CACHE_FILE if File.exist?(CACHE_FILE)
62
+ end
63
+
64
+ CACHE_FILE = File.expand_path('~/.sensible-cinema-ocr.marshal')
65
+
66
+ def serialize_cache_to_disk
67
+ File.binwrite(CACHE_FILE, Marshal.dump(CACHE))
68
+ end
69
+
70
+ def unserialize_cache_from_disk
71
+ if File.exist? CACHE_FILE
72
+ CACHE.merge!(Marshal.load File.binread(CACHE_FILE))
73
+ end
74
+
75
+ end
76
+
50
77
  extend self
51
78
 
52
79
  end
data/lib/overlayer.rb CHANGED
@@ -34,9 +34,9 @@ class OverLayer
34
34
  Muter.unmute! unless defined?($AM_IN_UNIT_TEST)
35
35
  end
36
36
 
37
- def blank!
37
+ def blank! seconds
38
38
  @am_blanked = true
39
- Blanker.blank_full_screen!
39
+ Blanker.blank_full_screen! seconds
40
40
  end
41
41
 
42
42
  def unblank!
@@ -58,7 +58,7 @@ class OverLayer
58
58
 
59
59
  def reload_yaml!
60
60
  @all_sequences = OverLayer.translate_yaml(File.read(@filename))
61
- puts '(re) loaded mute sequences from ' + File.basename(@filename) + ' as', pretty_sequences.pretty_inspect, "" unless $AM_IN_UNIT_TEST
61
+ puts '(re) loaded mute sequences from ' + File.basename(@filename) + ' as', pretty_sequences.pretty_inspect, "" unless defined?($AM_IN_UNIT_TEST)
62
62
  signal_change
63
63
  end
64
64
 
@@ -116,11 +116,11 @@ class OverLayer
116
116
  end
117
117
 
118
118
  if start2 == endy2 || endy2 < start2
119
- p 'warning--found a line that had poor interval', start, endy, type unless $AM_IN_UNIT_TEST
119
+ p 'warning--found a line that had poor interval', start, endy, type unless defined?($AM_IN_UNIT_TEST)
120
120
  next
121
121
  end
122
122
  if(endy2 > 60*60*3)
123
- p 'warning--found setting past 3 hours [?]', start, endy, type unless $AM_IN_UNIT_TEST
123
+ p 'warning--found setting past 3 hours [?]', start, endy, type unless defined?($AM_IN_UNIT_TEST)
124
124
  end
125
125
  new[start2] = endy2
126
126
  }
@@ -189,7 +189,7 @@ class OverLayer
189
189
  end
190
190
  end
191
191
  check_reload_yaml
192
- time + state + "(r,d,v,q to quit): "
192
+ time + state + "(r,d,v, or q to quit): "
193
193
  end
194
194
 
195
195
  def keyboard_input char
@@ -211,7 +211,7 @@ class OverLayer
211
211
  p 'set debug to', $DEBUG
212
212
  return
213
213
  when ' ' then
214
- puts cur_english_time
214
+ puts 'timestamp:' + cur_english_time
215
215
  return
216
216
  when 'r' then
217
217
  reload_yaml!
@@ -335,8 +335,10 @@ class OverLayer
335
335
  end
336
336
 
337
337
  def display_change change
338
- puts ''
339
- puts change + ' at ' + cur_english_time if $VERBOSE unless $DEBUG # too chatty for unit tests
338
+ puts '' unless defined?($AM_IN_UNIT_TEST)
339
+ if $VERBOSE
340
+ puts change + ' at ' + cur_english_time
341
+ end
340
342
  end
341
343
 
342
344
  def set_states!
@@ -344,7 +346,6 @@ class OverLayer
344
346
 
345
347
  if should_be_muted && !muted?
346
348
  mute!
347
- puts ''
348
349
  display_change 'muted'
349
350
  end
350
351
 
@@ -354,7 +355,7 @@ class OverLayer
354
355
  end
355
356
 
356
357
  if should_be_blank && !blank?
357
- blank!
358
+ blank! "%.02f" % (next_point - cur_time)
358
359
  display_change 'blanked'
359
360
  end
360
361
 
@@ -38,6 +38,7 @@ class ScreenTracker
38
38
  raise 'poor width or wrong window' if @x2 > max_x || @x2 == x
39
39
  raise 'poor height or wrong window' if @y2 > max_y || @y2 == y
40
40
  @digits = digits
41
+ @displayed_warning = false
41
42
  pps 'using x',@x, 'from x', x, 'y', @y, 'from y', y,'x2',@x2,'y2',@y2,'digits', @digits if $VERBOSE
42
43
  end
43
44
 
@@ -61,15 +62,18 @@ class ScreenTracker
61
62
 
62
63
  end
63
64
 
65
+ # gets the snapshot of "all the digits together"
64
66
  def get_bmp
65
67
  # Note: we no longer bring the window to the front tho...which it needs to be in both XP and Vista to work...sigh.
66
68
  Win32::Screenshot::BitmapMaker.capture_area(@hwnd,@x,@y,@x2,@y2) {|h,w,bmp| return bmp}
67
69
  end
68
70
 
71
+ # gets snapshot of the full window
69
72
  def get_full_bmp
70
- Win32::Screenshot.hwnd(@hwnd, 0) {|h,w,bmp| return bmp}
73
+ Win32::Screenshot::BitmapMaker.capture_all(@hwnd) {|h,w,bmp| return bmp}
71
74
  end
72
-
75
+
76
+ # writes out all screen tracking info to various files in the current pwd
73
77
  def dump_bmp filename = 'dump.bmp'
74
78
  File.binwrite filename, get_bmp
75
79
  File.binwrite 'all.' + filename, get_full_bmp
@@ -78,9 +82,12 @@ class ScreenTracker
78
82
 
79
83
  def dump_digits
80
84
  if @digits
85
+ @digit_count ||= 1
86
+ @digit_count += 1
81
87
  for type, bitmap in get_digits_as_bitmaps
82
- File.binwrite type.to_s + '.bmp', bitmap
88
+ File.binwrite type.to_s + '.' + @digit_count.to_s + '.bmp', bitmap
83
89
  end
90
+ print 'wrote digits:', @digit_count, "\n"
84
91
  end
85
92
  end
86
93
 
@@ -118,57 +125,66 @@ class ScreenTracker
118
125
  current = get_bmp
119
126
  if current != original
120
127
  if @digits
121
- return attempt_to_get_time_from_screen
128
+ got = attempt_to_get_time_from_screen
129
+ if @displayed_warning && got
130
+ # reassure user :)
131
+ p 'tracking it successfully again'
132
+ @displayed_warning = false
133
+ end
134
+ return got
122
135
  else
123
136
  puts 'screen time change only detected...'
137
+ return
124
138
  end
125
- return
126
139
  end
127
140
  sleep 0.02
128
141
  if(Time.now - time_since_last > 5)
129
- p 'warning--unable to track for some reason--may need to restart sensible-cinema'
142
+ p 'warning--unable to track screen time for some reason' unless @displayed_warning
130
143
  time_since_last = Time.now
131
- # reget it, just in case...
144
+ @displayed_warning = true
145
+ # reget window, just in case that's the problem...
132
146
  get_hwnd
133
147
  end
134
148
  }
135
149
  end
136
150
 
137
151
  def attempt_to_get_time_from_screen
138
- out = {}
139
- dump_digits if $DEBUG
140
- digits = get_digits_as_bitmaps # 0.08s [!] not too accurate...
141
- start = Time.now
142
- DIGIT_TYPES.each{|type|
143
- if digits[type]
144
- digit = identify_digit(digits[type])
145
- unless digit
146
- if $DEBUG || $VERBOSE
147
- @a ||= 1
148
- @a += 1
149
- p 'unable to identify digit!' + type.to_s + @a.to_s
150
- File.binwrite("bad_digit#{@a}#{type}.bmp", digits[type]) unless type == :hours
151
- end
152
- if type == :hours
153
- digit = 0 # this one can fail in VLC
154
- else
155
- # early return
156
- p 'identity failure' if $VERBOSE
157
- return
158
- end
159
- end
160
- out[type] = digit
161
- else
162
- # there isn't one on screen, so probably zero...
163
- out[type] = 0
152
+ out = {}
153
+ dump_digits if $DEBUG
154
+ digits = get_digits_as_bitmaps # 0.08s [!] not too accurate...ltodo
155
+ start = Time.now
156
+ DIGIT_TYPES.each{|type|
157
+ if digits[type]
158
+ digit = identify_digit(digits[type])
159
+ unless digit
160
+ if $DEBUG || $VERBOSE
161
+ @a ||= 1
162
+ @a += 1
163
+ @already_wrote ||= {}
164
+ unless @already_wrote[digits[type]]
165
+ p 'unable to identify capture!' + type.to_s + @a.to_s
166
+ File.binwrite("bad_digit#{@a}#{type}.bmp", digits[type]) unless type == :hours
167
+ @already_wrote[digits[type]] = true
164
168
  end
165
- }
166
- out = "%d:%d%d:%d%d" % DIGIT_TYPES.map{|type| out[type]}
167
- p 'got new screen time ' + out + " delta:" + (Time.now - start).to_s if $VERBOSE
168
- # if the window was in the background it will be all zeroes, so nil it out
169
- out = nil unless out =~ /[1-9]/
170
- return out, Time.now-start
169
+ end
170
+ if type == :hours
171
+ digit = 0 # this one can fail in VLC
172
+ else
173
+ # early return
174
+ p 'identity failure ' + type.to_s if $VERBOSE
175
+ return
176
+ end
171
177
  end
178
+ out[type] = digit
179
+ else
180
+ # there isn't one specified as being on screen, so assume it is always zero (like youtube hour)...
181
+ out[type] = 0
182
+ end
183
+ }
184
+ out = "%d:%d%d:%d%d" % DIGIT_TYPES.map{ |type| out[type] }
185
+ puts '', 'got new screen time ' + out + " tracking delta:" + (Time.now - start).to_s if $VERBOSE
186
+ return out, Time.now-start
187
+ end
172
188
 
173
189
  def process_forever_in_thread
174
190
  Thread.new {
data/spec/blanker.spec.rb CHANGED
@@ -2,16 +2,24 @@ require File.dirname(__FILE__) + '/common'
2
2
  require_relative '../lib/blanker.rb'
3
3
 
4
4
  describe Blanker do
5
+
6
+ before(:each) do
7
+ Blanker.startup
8
+ end
5
9
 
10
+ after(:each) do
11
+ Blanker.shutdown
12
+ end
13
+
6
14
  it "should be able to blank then unblank" do
7
- Blanker.blank_full_screen!
8
- sleep 3
15
+ Blanker.blank_full_screen! "2.000"
16
+ sleep 2
9
17
  Blanker.unblank_full_screen!
10
18
  end
11
19
 
12
20
  it "should be able to blank several times" do
13
21
  3.times {
14
- Blanker.blank_full_screen!
22
+ Blanker.blank_full_screen! ''
15
23
  Blanker.unblank_full_screen!
16
24
  }
17
25
  end
@@ -26,7 +34,7 @@ describe Blanker do
26
34
 
27
35
  it "should be able to blank certain coords"
28
36
 
29
- it "should have a color optionally"
37
+ it "should have a background color optionally"
30
38
 
31
39
  it "should have a picture optionally"
32
40
 
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/spec/ocr.spec.rb CHANGED
@@ -1,5 +1,8 @@
1
1
  require File.dirname(__FILE__) + '/common'
2
2
  require_relative "../lib/ocr"
3
+ require 'benchmark'
4
+
5
+ $OCR_NO_CACHE = true
3
6
 
4
7
  describe OCR do
5
8
 
@@ -7,31 +10,80 @@ describe OCR do
7
10
  OCR.version.should_not be_blank
8
11
  end
9
12
 
10
- it "should be able to grab some digits" do
11
- success = true
12
- for file in Dir['images/*[0-9].bmp']
13
+ Dir['images/*[0-9].bmp'].each{ |file|
14
+ it "should be able to OCR #{file}" do
13
15
  options = {}
14
16
  options[:should_invert] = true if file =~ /hulu/
15
17
  file =~ /(.)\.bmp/
16
18
  expected_digit = $1.to_i
17
19
  if OCR.identify_digit(File.binread(file), options) != expected_digit
18
20
  p "fail:" + file
19
- require 'ruby-debug'
20
- debugger
21
- OCR.identify_digit(File.binread(file), options)
22
- success = false
21
+ begin
22
+ require 'ruby-debug'
23
+ debugger
24
+ OCR.identify_digit(File.binread(file), options)
25
+ rescue LoadError
26
+ puts 'unable to load ruby-debug'
27
+ end
28
+ fail
23
29
  end
24
30
  end
25
- fail unless success
26
- end
31
+ }
27
32
 
28
33
  it "should be able to grab a colon" do
29
- pending "caring about colons"
30
- OCR.identify_digit(File.binread("images/colon.bmp"), :might_be_colon => true).should == ":"
34
+ pending "caring about colons" do
35
+ OCR.identify_digit(File.binread("images/colon.bmp"), :might_be_colon => true).should == ":"
36
+ end
37
+ end
38
+
39
+ def read_digit
40
+ OCR.identify_digit(File.binread("images/youtube_3_0.bmp"))
31
41
  end
32
42
 
33
43
  it "should return nil if it can't identify a digit" do
34
44
  OCR.identify_digit(File.binread("images/black.bmp")).should be_nil
35
45
  end
36
46
 
47
+ context "cache" do
48
+
49
+ before do
50
+ OCR.clear_cache!
51
+ $OCR_NO_CACHE = false
52
+ end
53
+
54
+ after do
55
+ $OCR_NO_CACHE = true
56
+ end
57
+
58
+ it "should cache results from one time to the next" do
59
+ original_time = Benchmark.realtime { read_digit }
60
+ new_time = Benchmark.realtime { 3.times { read_digit } }
61
+ new_time.should be < original_time
62
+ end
63
+
64
+ it "should not cache results for failed reads" do
65
+ original_time = Benchmark.realtime { OCR.identify_digit(File.binread("images/black.bmp")) }
66
+ new_time = Benchmark.realtime { 3.times { OCR.identify_digit(File.binread("images/black.bmp"))} }
67
+ new_time.should be > original_time
68
+ end
69
+
70
+ it "should serialize creating a cache file" do
71
+ Pathname.new(OCR::CACHE_FILE).should_not exist
72
+ OCR.serialize_cache_to_disk
73
+ Pathname.new(OCR::CACHE_FILE).should exist
74
+ end
75
+
76
+ it "should use the cache file to speed things up on startup" do
77
+ long = Benchmark.realtime { read_digit }
78
+ OCR.serialize_cache_to_disk
79
+ OCR::CACHE.clear
80
+ long2 = Benchmark.realtime { read_digit }
81
+ OCR.unserialize_cache_from_disk
82
+ short = Benchmark.realtime { 3.times { read_digit } }
83
+ long.should be > short
84
+ long2.should be > short
85
+ end
86
+
87
+ end
88
+
37
89
  end
@@ -22,11 +22,13 @@ describe OverLayer do
22
22
  before do
23
23
  File.write 'temp.yml', YAML.dump({:mutes => {2.0 => 4.0}} )
24
24
  @o = OverLayer.new('temp.yml')
25
+ Blanker.startup
25
26
  end
26
27
 
27
28
  after do
28
29
  Thread.join_all_others
29
30
  File.delete 'temp.yml'
31
+ Blanker.shutdown
30
32
  end
31
33
 
32
34
  def start_good
@@ -131,7 +133,7 @@ describe OverLayer do
131
133
  end
132
134
 
133
135
  it 'should have key list output on screen' do
134
- @o.status.should include("r,d,v,q to quit")
136
+ @o.status.should include("q to quit")
135
137
  end
136
138
 
137
139
  it 'should allow for yaml input and parse it appropo' do
@@ -407,7 +409,7 @@ describe OverLayer do
407
409
 
408
410
  it "should not fail with verbose on, after it's past next states" do
409
411
  at(500_000) do
410
- @o.status.should == "Current time: 138:53:20.0 no more actions after this point...(r,d,v,q to quit): "
412
+ @o.status.should == "Current time: 138:53:20.0 no more actions after this point...(r,d,v, or q to quit): "
411
413
  end
412
414
  end
413
415
 
@@ -18,8 +18,7 @@ describe ScreenTracker do
18
18
  rescue
19
19
  silence = File.expand_path("./silence.wav").gsub("/", "\\")
20
20
  Dir.chdir("/program files/VideoLan/VLC") do; IO.popen("vlc.exe #{silence}").pid; end # work around for jruby...
21
- sleep 4
22
-
21
+ sleep 4
23
22
  $pid1 = GetPid.get_process_id_from_window(Win32::Screenshot::Util.window_hwnd(SILENCE)) # more jruby work-arounds...
24
23
  end
25
24
  end
@@ -165,7 +164,7 @@ describe ScreenTracker do
165
164
  context "using OCR" do
166
165
 
167
166
  before do
168
- @a = ScreenTracker.new_from_yaml File.read("../zamples/players/total_length_under_an_hour/vlc_non_full_screened.yml"), nil
167
+ @a = ScreenTracker.new_from_yaml File.read("../zamples/players/vlc/non_full_screened_total_length_under_an_hour.yml"), nil
169
168
  end
170
169
 
171
170
  it "should be able to disk dump snapshotted digits" do
@@ -217,7 +216,7 @@ describe ScreenTracker do
217
216
  output[0].should_not be_nil
218
217
  old_handle.should_not == @a.hwnd
219
218
  end
220
-
219
+
221
220
  end
222
221
 
223
222
  def kill_vlc
@@ -0,0 +1,17 @@
1
+ name: desktop
2
+ x: 77
3
+ y : 745
4
+ width: 28
5
+ height: 12
6
+ digits:
7
+ :hours:
8
+ :minute_tens:
9
+ :minute_ones:
10
+ - 77
11
+ - 8
12
+ :second_tens:
13
+ - 88
14
+ - 8
15
+ :second_ones:
16
+ - 96
17
+ - 8
@@ -0,0 +1,17 @@
1
+ name: desktop
2
+ x: 85
3
+ y : 839
4
+ width: 31
5
+ height: 17
6
+ digits:
7
+ :hours:
8
+ :minute_tens:
9
+ :minute_ones:
10
+ - 86
11
+ - 11
12
+ :second_tens:
13
+ - 99
14
+ - 9
15
+ :second_ones:
16
+ - 108
17
+ - 9
@@ -0,0 +1,17 @@
1
+ name: desktop
2
+ x: 125
3
+ y : -37
4
+ width: 46
5
+ height: 19
6
+ digits:
7
+ :hours:
8
+ :minute_tens:
9
+ :minute_ones:
10
+ - 127
11
+ - 13
12
+ :second_tens:
13
+ - 145
14
+ - 12
15
+ :second_ones:
16
+ - 158
17
+ - 11
@@ -0,0 +1,8 @@
1
+ mutes:
2
+ # none
3
+ blank_outs:
4
+ "0:01:02" : "0:01:06" # bum waggin'
5
+
6
+ title: The Gummy Bear Song - Long English Version (probably works with other languages')
7
+ source: youtube
8
+ url: http://www.youtube.com/watch?v=astISOttCQ0
@@ -0,0 +1,9 @@
1
+ mutes:
2
+ # none
3
+ blank_outs:
4
+ # bum wigglin'
5
+ "00:46.5" : "00:48.5"
6
+ "02:18.5" : "02:20"
7
+ title: Nuki Song
8
+ source: youtube
9
+ url: http://www.youtube.com/watch?v=xd12hR68sWM
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 7
8
- - 7
9
- version: 0.7.7
7
+ - 9
8
+ - 3
9
+ version: 0.9.3
10
10
  platform: ruby
11
11
  authors:
12
12
  - Roger Pack
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-08-16 00:00:00 -06:00
17
+ date: 2010-08-18 00:00:00 -06:00
18
18
  default_executable: sensible-cinema
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -133,6 +133,7 @@ files:
133
133
  - ext/mkrf_conf.rb
134
134
  - gplv3.txt
135
135
  - lib/blanker.rb
136
+ - lib/fake_blanker.rb
136
137
  - lib/file_chooser.rb
137
138
  - lib/keyboard_input.rb
138
139
  - lib/mouse.rb
@@ -165,12 +166,25 @@ files:
165
166
  - spec/images/vlc_6.bmp
166
167
  - spec/images/vlc_9.bmp
167
168
  - spec/images/vlc_colon.bmp
169
+ - spec/images/youtube_0.bmp
170
+ - spec/images/youtube_1.bmp
171
+ - spec/images/youtube_2_0.bmp
172
+ - spec/images/youtube_2_5.bmp
173
+ - spec/images/youtube_2_6.bmp
174
+ - spec/images/youtube_3_0.bmp
175
+ - spec/images/youtube_4.bmp
176
+ - spec/images/youtube_4_0.bmp
177
+ - spec/images/youtube_5.bmp
178
+ - spec/images/youtube_6.bmp
179
+ - spec/images/youtube_small_0.bmp
180
+ - spec/images/youtube_small_2.bmp
181
+ - spec/images/youtube_small_2_0.bmp
182
+ - spec/images/youtube_small_4.bmp
168
183
  - spec/keyboard_input.spec.rb
169
184
  - spec/mouse.spec.rb
170
185
  - spec/mouse_forever.rb
171
186
  - spec/muter.spec.rb
172
187
  - spec/ocr.spec.rb
173
- - spec/open.bat
174
188
  - spec/overlayer.spec.rb
175
189
  - spec/screen_tracker.spec.rb
176
190
  - spec/silence.wav
@@ -199,17 +213,21 @@ files:
199
213
  - vendor/imagemagick/msvcr90.dll
200
214
  - vendor/imagemagick/vcomp90.dll
201
215
  - zamples/players/how_to_create_a_new_player_description.txt
202
- - zamples/players/sample_snapshots/utube.JPG
203
- - zamples/players/sample_snapshots/youtube full screen big screen.jpg
204
- - zamples/players/total_length_over_an_hour/hulu_full_screened.yml
205
- - zamples/players/total_length_over_an_hour/vlc_full_screened.yml
206
- - zamples/players/total_length_over_an_hour/vlc_windowed.yml
207
- - zamples/players/total_length_under_an_hour/vlc_non_full_screened.yml
208
- - zamples/scene_lists/categories.yml
216
+ - zamples/players/hulu/total_length_over_an_hour.yml
217
+ - zamples/players/vlc/full_screened_total_length_over_an_hour.yml
218
+ - zamples/players/vlc/non_full_screened_total_length_under_an_hour.yml
219
+ - zamples/players/vlc/vlc_windows_total_length_over_an_hour.yml
220
+ - zamples/players/youtube/full_screened_1024x768.yml
221
+ - zamples/players/youtube/full_screened_1152x864.yml
222
+ - zamples/players/youtube/full_screened_1680x1050.yml
223
+ - zamples/players/youtube/note_these_assume_less_than_10_minutes_length.txt
224
+ - zamples/scene_lists/category descriptions.yml
209
225
  - zamples/scene_lists/disney_cars.yml
210
226
  - zamples/scene_lists/example_scene_list.yml
227
+ - zamples/scene_lists/gummy_bear_song_youtube.yml
211
228
  - zamples/scene_lists/happy_feet_dvd.yml
212
229
  - zamples/scene_lists/labyrinth.yml
230
+ - zamples/scene_lists/nuki_song_youtube.yml
213
231
  - zamples/scene_lists/star_trek_generations_hulu.yml
214
232
  has_rdoc: true
215
233
  homepage: http://github.com/rdp
data/spec/open.bat DELETED
@@ -1 +0,0 @@
1
- "/program files/VideoLan/VLC/vlc.exe" silence.wav