storyboard 0.2.4 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,3 +1,8 @@
1
1
  *.avi
2
2
  *.mkv
3
+ *.pdf
4
+ *.gem
5
+ *.log
6
+ *.png
7
+ *.xml*
3
8
  .DS_Store
data/.rvmrc CHANGED
@@ -1 +1 @@
1
- rvm --create use 1.9.3@storyboard
1
+ rvm --create use 1.9.3-p327@storyboard
data/Gemfile CHANGED
@@ -2,11 +2,4 @@ source :rubygems
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'tvdb_party', :git => 'https://github.com/nddrylliog/tvdb_party'
6
- gem 'nokogiri'
7
5
  gem 'suby', :path => 'vendor/suby', :require => 'suby'
8
- gem 'rmagick'
9
- gem 'prawn'
10
- gem 'ruby-progressbar'
11
- gem 'rubyzip'
12
- gem 'levenshtein-ffi', :require => 'levenshtein'
data/Gemfile.lock CHANGED
@@ -1,20 +1,13 @@
1
- GIT
2
- remote: https://github.com/nddrylliog/tvdb_party
3
- revision: 60ce3c28e664078da0206075e025ee06547f5826
4
- specs:
5
- tvdb_party (0.6.2)
6
- httparty (>= 0.6.1)
7
-
8
1
  PATH
9
2
  remote: .
10
3
  specs:
11
- storyboard (0.2.3)
4
+ storyboard (0.3.0)
12
5
  levenshtein-ffi
13
6
  mime-types (>= 1.19)
7
+ mini_magick
14
8
  nokogiri
15
9
  path (>= 1.3.0)
16
10
  prawn
17
- rmagick
18
11
  ruby-progressbar
19
12
  rubyzip
20
13
  term-ansicolor
@@ -36,15 +29,12 @@ GEM
36
29
  afm (0.2.0)
37
30
  ffi (1.1.5)
38
31
  hashery (2.1.0)
39
- httparty (0.10.0)
40
- multi_json (~> 1.0)
41
- multi_xml
42
32
  levenshtein-ffi (1.0.3)
43
33
  ffi
44
34
  ffi (~> 1.1.5)
45
35
  mime-types (1.19)
46
- multi_json (1.5.0)
47
- multi_xml (0.5.2)
36
+ mini_magick (3.4)
37
+ subexec (~> 0.2.1)
48
38
  nokogiri (1.5.6)
49
39
  path (1.3.1)
50
40
  pdf-reader (1.3.0)
@@ -56,10 +46,10 @@ GEM
56
46
  prawn (0.12.0)
57
47
  pdf-reader (>= 0.9.0)
58
48
  ttfunk (~> 1.0.2)
59
- rmagick (2.13.1)
60
49
  ruby-progressbar (1.0.2)
61
50
  ruby-rc4 (0.1.5)
62
51
  rubyzip (0.9.9)
52
+ subexec (0.2.2)
63
53
  term-ansicolor (1.0.7)
64
54
  ttfunk (1.0.3)
65
55
 
@@ -67,12 +57,5 @@ PLATFORMS
67
57
  ruby
68
58
 
69
59
  DEPENDENCIES
70
- levenshtein-ffi
71
- nokogiri
72
- prawn
73
- rmagick
74
- ruby-progressbar
75
- rubyzip
76
60
  storyboard!
77
61
  suby!
78
- tvdb_party!
data/INSTALL.md ADDED
@@ -0,0 +1,26 @@
1
+ # Installing Storybard
2
+
3
+ Storyboard relies on a number of external libraries to handle extracting information from the video files and generating the output. Primarily, it requires Ruby 1.9.3 or greater, FFMpeg 1.1 or greater, Imagemagick (which in turn requires ghostscript), and a compiler.
4
+
5
+ ## OS X
6
+
7
+ To begin, you'll need to download GCC, a set of tools that will let you compile low level code. You can find a nice installer for it at [osx-gcc-installer](https://github.com/kennethreitz/osx-gcc-installer). Once GCC is installed, download and install [homebrew](http://mxcl.github.com/homebrew/), which is a tool that will automate of the installation process for Imagemagick and FFmpeg. If you haven't installed homebrew before, open a Terminal window and do the following:
8
+
9
+ ruby -e "$(curl -fsSkL raw.github.com/mxcl/homebrew/go)"
10
+ brew install ffmpeg imagemagick ghostscript
11
+
12
+ If you've already installed homebrew, update it and re-install FFmpeg if necessary. Storyboard requires FFmpeg 1.1, which became available on homebrew in Janurary 2013.
13
+
14
+ brew update
15
+ brew uninstall ffmpeg
16
+ brew upgrade ffmpeg
17
+
18
+ Finally, if you don't have Ruby 1.9.3 installed on your system, you can use <a href="http://rvm.io">RVM</a> to install it. In a termal window, run the following:
19
+
20
+ curl -L https://get.rvm.io | bash -s stable --ruby
21
+ rvm install 1.9.3-p374
22
+ rvm default 1.9.3-p374
23
+
24
+ When all of those are installed, you can install Storyboard with the `gem` command
25
+
26
+ gem install storyboard
data/README.md CHANGED
@@ -1,16 +1,22 @@
1
1
  # Storyboard
2
2
 
3
- Read the TV and Movies you don't have time to watch.
3
+ Read the TV and Movies you don't have time to watch. Given a video file, it will generate a PDF (or soon, ePub and Mobi) containing every scene change and line of dialog.
4
4
 
5
5
  ## Storyboard
6
6
 
7
7
  ![Seinfeld](http://i.imgur.com/lTRuC.jpg)
8
8
 
9
- Storyboard is _very much_ a work in progress, and only works (most of) some of the time. Using it is simple:
9
+ Storyboard is _very much_ a work in progress, though it works most of the time. Using it is simple:
10
10
 
11
- storyboard /path/to/video-file.mkv
11
+ $ storyboard /path/to/video-file.mkv
12
12
 
13
- Storyboard will try to generate a file at `/path/to/video-file.pdf` containing the final product. ePub and Mobi support will come later.
13
+ Storyboard will try to generate a file at `/path/to/video-file.pdf` containing the final product. Simiarly, you can pass in the path to a folder containing multiple files and it will output a PDF for each video it finds.
14
+
15
+ $ ls "~/TV/ShowName/Season 1"
16
+ ShowName.1x01.EpisodeName.mkv ShowName.1x02.AnotherEpisode.mkv ShowName.1x03.ThirdEp.mkv
17
+ $ storyboard "~/TV/ShowName/Season 1"
18
+ $ ls .
19
+ ShowName.1x01.EpisodeName.pdf ShowName.1x02.AnotherEpisode.pdf ShowName.1x03.ThirdEp.pdf
14
20
 
15
21
  You can see available commands by running the program without any options
16
22
 
@@ -23,21 +29,9 @@ You can see available commands by running the program without any options
23
29
  (pdf, mobi, epub)
24
30
  -h, --help Show this message
25
31
 
26
- ## Requirements
27
-
28
- Storyboard requires a recent version of *ffmpeg*. This gem includes a build of *ffprobe* that will only work on OS X 1.8, 64 bit. It's probably best not to use this on any different system for now. It's also best to run it on something with at least 8 cores.
29
32
 
30
- ## Known Issues
31
-
32
- * If there is a scene change followed by dialog in the next frame or two, the dialog may not be shown.
33
- * Subtitles are always downloaded, never extracted from video files. Because the subtitles are searched for based on the filename it's best that you have then named in a standard format, e.g., `The X-Files - 1x21 - Tooms.avi`.
34
- * Sometimes the wrong subtitle file will be returned from the site. In those cases, download it manually and use the `-s` option to pass in the path to an SRT formatted subtitle file. This is because the data lies, and there's nothing I can do about it.
35
- * Some subtitles are encoded in UTF-16, and I haven't care quite enough yet to get them to work. Others use bad UTF8.
36
- * The subtitles are uuuuuugly.
37
- * Hardcoding 8 for the number of threads is a bad idea
38
- * Almost definitely some path-escaping issues, so avoid files with apostrophes and slashes
39
- * Some subtitles put all the text on one line, so that has to get broken up.
33
+ ## Requirements
40
34
 
41
- ## Help
35
+ The INSTALL.md file talks about requirements some more, but Storyboard requires Ruby 1.9.3, FFMpeg 1.1, and any recent version of Imagemagick. If you already have those available, just install the storyboard gem.
42
36
 
43
- For now, best to email me theothermarkolson@gmail.com
37
+ gem install storyboard
data/bin/storyboard CHANGED
@@ -9,15 +9,19 @@ require 'bundler'
9
9
  ENV['BUNDLE_GEMFILE'] = File.join(File.dirname(__FILE__), '../Gemfile')
10
10
  Bundler.require(:default)
11
11
 
12
- require 'nokogiri'
13
- require 'suby'
14
- require 'rmagick'
15
- require 'prawn'
16
- require 'ruby-progressbar'
17
-
18
12
  $LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib"
19
13
  require 'storyboard'
20
14
 
15
+ unless Storyboard.ffprobe_installed?
16
+ puts "Storyboard requires FFmpeg 1.1. Please check the README for instructions"
17
+ exit
18
+ end
19
+
20
+ unless Storyboard.magick_installed?
21
+ puts "Storyboard requires Imagemagick's mogrify tool. Please check the README for instructions on how to install Imagemagick if you need them."
22
+ exit
23
+ end
24
+
21
25
  options = {:scenes => true, :verbose => true, :types => ['pdf'], :scene_threshold => 0.4}
22
26
 
23
27
  # think about them
@@ -67,16 +71,37 @@ if ARGV.size < 1
67
71
  puts "videofile required"
68
72
  puts opts.to_s
69
73
  exit 1
74
+ elsif ARGV.size == 2 && !File.directory?(File.realdirpath(ARGV.last))
75
+ puts "outputdir #{ARGV.last} is not a directory"
76
+ puts opts.to_s
77
+ exit 1
78
+ elsif ARGV.size > 2
79
+ puts "Too many arguments"
80
+ puts opts.to_s
81
+ exit 1
70
82
  end
71
83
 
72
- options[:file] = File.realdirpath(ARGV.shift)
84
+ options[:vidpath] = File.realdirpath(ARGV.shift)
85
+ options[:write_to] = ARGV.shift || Dir.pwd
73
86
 
74
- output_dir = ARGV.shift || Dir.pwd
75
- options[:basename] = File.basename(options[:file], ".*")
87
+ if !File.exists?(options[:vidpath])
88
+ puts("#{options[:vidpath]} doesn't exist.")
89
+ exit
90
+ end
91
+
92
+ filepaths = []
76
93
 
77
- options[:write_to] = output_dir #File.join(output_dir,options[:basename])
78
- options[:work_dir] = Dir.mktmpdir
79
- Dir.mkdir(options[:write_to]) unless File.directory?(options[:write_to])
80
- LOG.debug(options)
94
+ if File.directory?(options[:vidpath])
95
+ LOG.info("Ignoring subtitle option because we're looking at a directory") if options[:subs]
96
+ options[:vidpath] = File.join(options[:vidpath], '*')
97
+ LOG.info("Reading video files in #{options[:vidpath]}")
98
+ filepaths += Dir[File.realdirpath(options[:vidpath])]
99
+ else
100
+ filepaths << options[:vidpath]
101
+ end
81
102
 
82
- Storyboard.new(options)
103
+ filepaths.each {|fp|
104
+ options[:file] = fp
105
+ runner = Storyboard.new(options)
106
+ runner.run if runner.video_file?
107
+ }
data/lib/storyboard.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'storyboard/subtitles.rb'
2
+ require 'storyboard/bincheck.rb'
2
3
  require 'storyboard/thread-util.rb'
3
4
  require 'storyboard/time.rb'
4
5
  require 'storyboard/version.rb'
@@ -7,38 +8,47 @@ require 'storyboard/generators/sub.rb'
7
8
  require 'storyboard/generators/pdf.rb'
8
9
 
9
10
  require 'mime/types'
11
+ require 'fileutils'
12
+ require 'tmpdir'
13
+
14
+ require 'ruby-progressbar'
15
+ require 'mini_magick'
10
16
 
11
17
  class Storyboard
12
18
  attr_accessor :options, :capture_points, :subtitles, :timings
13
- attr_accessor :length, :renderers
19
+ attr_accessor :length, :renderers, :mime
14
20
 
15
21
  def initialize(o)
16
22
  @capture_points = []
17
23
  @renderers = []
18
24
  @options = o
19
25
 
20
- @options[:save_directory] = File.join(o[:work_dir], 'raw_frames')
26
+ check_video
27
+ end
21
28
 
22
- Dir.mkdir(@options[:save_directory]) unless File.directory?(@options[:save_directory])
29
+ def run
30
+ LOG.info("Processing #{options[:file]}")
31
+ setup
23
32
 
24
33
  @subtitles = SRT.new(options[:subs] ? File.read(options[:subs]) : get_subtitles, options)
25
- # temp hack so I don't have to wait all the time.
34
+ # bit of a temp hack so I don't have to wait all the time.
26
35
  @subtitles.save if options[:verbose]
27
36
 
37
+
28
38
  @renderers << Storyboard::PDFRenderer.new(self) if options[:types].include?('pdf')
29
39
 
30
- check_video
31
40
  run_scene_detection if options[:scenes]
32
41
  consolidate_frames
33
42
  extract_frames
34
43
  render_output
44
+
45
+ cleanup
35
46
  end
36
47
 
37
48
  def run_scene_detection
38
- LOG.info("Scanning for scene changes. This may take a moment.")
39
49
  pbar = ProgressBar.create(:title => " Analyzing Video", :format => '%t [%B] %e', :total => @length, :smoothing => 0.6)
40
50
  bin = File.join(File.dirname(__FILE__), '../bin/storyboard-ffprobe')
41
- Open3.popen3(bin, "-show_frames", "-of", "compact=p=0", "-f", "lavfi", %(movie=#{options[:file]},select=gt(scene\\,.30)), "-pretty") {|stdin, stdout, stderr, wait_thr|
51
+ Open3.popen3('ffprobe', "-show_frames", "-of", "compact=p=0", "-f", "lavfi", %(movie=#{options[:file]},select=gt(scene\\,.30)), "-pretty") {|stdin, stdout, stderr, wait_thr|
42
52
  begin
43
53
  # trolololol
44
54
  o = stdout.gets.split('|').inject({}){|hold,value| s = value.split('='); hold[s[0]]=s[1]; hold }
@@ -69,7 +79,7 @@ class Storyboard
69
79
  end
70
80
 
71
81
  def extract_frames
72
- pool = Thread::Pool.new(8)
82
+ pool = Thread::Pool.new(2)
73
83
  pbar = ProgressBar.create(:title => " Extracting Frames", :format => '%t [%c/%C|%B] %e', :total => @capture_points.count)
74
84
 
75
85
  @capture_points.each_with_index {|f,i|
@@ -93,7 +103,6 @@ class Storyboard
93
103
  end
94
104
 
95
105
  def render_output
96
- LOG.info("Rendering output files")
97
106
  pbar = ProgressBar.create(:title => " Rendering Output", :format => '%t [%c/%C|%B] %e', :total => @capture_points.count)
98
107
  @capture_points.each_with_index {|f,i|
99
108
  image_name = File.join(@options[:save_directory], "%04d.jpg" % [i])
@@ -111,9 +120,31 @@ class Storyboard
111
120
  end
112
121
 
113
122
  def check_video
114
- LOG.debug MIME::Types.type_for(options[:file])
115
- @length = `ffmpeg -i "#{options[:file]}" 2>&1 | grep "Duration" | cut -d ' ' -f 4 | sed s/,//`
116
- @length = STRTime.parse(length.strip+'0').value
123
+ @mime = MIME::Types.type_for(options[:file])
124
+ if video_file?
125
+ @length = `ffmpeg -i "#{options[:file]}" 2>&1 | grep "Duration" | cut -d ' ' -f 4 | sed s/,//`
126
+ @length = STRTime.parse(length.strip+'0').value
127
+ end
128
+ end
129
+
130
+ def video_file?
131
+ !@mime.grep(/video\//).empty?
132
+ end
133
+
134
+ def mkv?
135
+ !@mime.grep(/matroska/).empty?
136
+ end
137
+
138
+ def setup
139
+ @options[:basename] = File.basename(options[:file], ".*")
140
+ @options[:work_dir] = Dir.mktmpdir
141
+ Dir.mkdir(@options[:write_to]) unless File.directory?(@options[:write_to])
142
+ @options[:save_directory] = File.join(@options[:work_dir], 'raw_frames')
143
+ Dir.mkdir(@options[:save_directory]) unless File.directory?(@options[:save_directory])
144
+ end
145
+
146
+ def cleanup
147
+ FileUtils.remove_dir(@options[:work_dir])
117
148
  end
118
149
 
119
150
  end
@@ -0,0 +1,34 @@
1
+ class Object
2
+ def command?(name)
3
+ `which #{name}`
4
+ $?.success?
5
+ end
6
+ end
7
+
8
+ class Storyboard
9
+ def self.mkvtools_installed?
10
+ command?("mkvextract") && command?("mkvmerge")
11
+ end
12
+
13
+ def self.mp4box_insatlled?
14
+ command?("MP4Box")
15
+ end
16
+
17
+ def self.magick_installed?
18
+ command?("mogrify")
19
+ end
20
+
21
+ def self.ffprobe_installed?
22
+ good = command?("ffprobe")
23
+ if good
24
+ version = `ffprobe -version`.scan(/version ([\d\.]+)\n/)
25
+ if version.empty?
26
+ good = false
27
+ else
28
+ float_version = version.first[0].to_f
29
+ good = float_version >= 1.1
30
+ end
31
+ end
32
+ return good
33
+ end
34
+ end
@@ -1,7 +1,5 @@
1
1
  require 'prawn'
2
-
3
- require 'rmagick'
4
- include Magick
2
+ require 'mini_magick'
5
3
 
6
4
  class Storyboard
7
5
  class PDFRenderer < Storyboard::Renderer
@@ -23,23 +21,25 @@ class Storyboard
23
21
  end
24
22
 
25
23
  def render_frame(frame_name, subtitle = nil)
26
- image_output = File.join(@storyboard.options[:save_directory], "sub-#{File.basename(frame_name)}")
27
- img = ImageList.new(frame_name)
24
+ output_filename = File.join(@storyboard.options[:save_directory], "sub-#{File.basename(frame_name)}")
25
+ image = MiniMagick::Image.open(frame_name)
28
26
 
29
27
  if(@dimensions.empty?)
30
- resize_height = (img.rows * (@storyboard.options[:max_width].to_f/img.columns)).ceil
28
+ resize_height = (image[:height] * (@storyboard.options[:max_width].to_f/image[:width])).ceil
31
29
  set_dimensions(storyboard.options[:max_width], resize_height)
32
30
  end
33
31
 
34
- img.resize_to_fit!(@dimensions[0], @dimensions[1])
32
+ image.resize "#{@dimensions[0]}x#{@dimensions[1]}"
33
+
34
+ self.add_subtitle(image, subtitle, @dimensions) if subtitle
35
+
36
+ image.format 'jpeg'
37
+ image.write(output_filename)
38
+ image.destroy!
35
39
 
36
- self.add_subtitle(img, subtitle) if subtitle
40
+ @pdf.image output_filename, :width => @dimensions[0], :height => @dimensions[1]
37
41
 
38
- img.format = 'jpeg'
39
- img.write(image_output) { self.quality = 60 }
40
- img.destroy!
41
42
 
42
- @pdf.image image_output, :width => @dimensions[0], :height => @dimensions[1]
43
43
  end
44
44
 
45
45
  end
@@ -1,32 +1,41 @@
1
+ require 'prawn'
1
2
  class Storyboard
2
3
  class Renderer
3
- def add_subtitle(img, subtitle)
4
- text = subtitle.lines.join("\n")
5
- txt = nil
6
- txtwidth = img.columns + 1
7
- txtsize = 29
8
- while(txtwidth > (img.columns * 0.8))
9
- txtsize -= 1
10
- txt = Draw.new
11
- txt.pointsize = txtsize
12
- o = txt.get_multiline_type_metrics(img, text)
13
- txtwidth = o.width
14
- end
4
+ @@size_canvas = Prawn::Document.new
5
+ def add_subtitle(image, subtitle, dimensions)
6
+ offset = 0
7
+ subtitle.lines.reverse.each_with_index {|caption,i|
8
+ escaped = caption.gsub(/\\|'|"/) { |c| "\\#{c}" }
9
+ font_size = 30
10
+ text_width = dimensions[0] + 1
11
+ while(text_width > (dimensions[0] * 0.9))
12
+ font_size -= 1
13
+ text_width = @@size_canvas.width_of(caption, :size => font_size)
14
+ end
15
15
 
16
- txt.gravity = Magick::SouthGravity
17
- txt.stroke_width = 1
18
- txt.stroke = 'transparent'
19
- txt.font_weight = Magick::BoldWeight
16
+ image.combine_options do |c|
17
+ c.font "helvetica"
18
+ c.fill "#333333"
19
+ c.strokewidth '1'
20
+ c.stroke '#000000'
21
+ c.pointsize font_size.to_s
22
+ c.gravity "south"
23
+ c.draw "text 0, #{offset} '#{escaped}'"
24
+ end
20
25
 
21
- img.annotate(txt, 0,0,-2,-2, text) {
22
- txt.fill = '#333333'
23
- }
26
+ #and the shadow
27
+ image.combine_options do |c|
28
+ c.font "helvetica"
29
+ c.fill "#ffffff"
30
+ c.strokewidth '1'
31
+ c.stroke 'transparent'
32
+ c.pointsize font_size.to_s
33
+ c.gravity "south"
34
+ c.draw "text -2, #{offset-2} '#{escaped}'"
35
+ end
24
36
 
25
- img.annotate(txt, 0,0,0,0, text){
26
- txt.fill = "#ffffff"
27
- txt.stroke = "#000000"
28
- }
29
- txt = nil
37
+ offset += (@@size_canvas.height_of(caption, :size => font_size)).ceil
38
+ }
30
39
  end
31
40
  end
32
41
  end
@@ -1,5 +1,29 @@
1
1
  class Storyboard
2
2
  def get_subtitles
3
+ extensionless = File.join(File.dirname(options[:file]), File.basename(options[:file], ".*") + '.srt')
4
+
5
+ if mkv?
6
+ if Storyboard.mkvtools_installed?
7
+ output = `mkvmerge -i "#{options[:file]}"`
8
+ subs = output.scan(/Track ID (\d+): subtitles \(S_TEXT\/UTF8\)/)
9
+ # until I can play with better output, take the first.
10
+ if not subs.empty?
11
+ LOG.info("Extracting embedded subtitles")
12
+ LOG.info("Multiple subtitles found in the mkv. Taking the first.") if subs.count > 1
13
+ `mkvextract tracks "#{options[:file]}" #{subs.first[0]}:"#{options[:work_dir]}/subtitles.srt"`
14
+ return File.read("#{options[:work_dir]}/subtitles.srt", )
15
+ end
16
+ else
17
+ LOG.debug("File is mkv, but no mkvtoolnix installed.")
18
+ end
19
+ end
20
+
21
+ if File.exists?(options[:file] + '.srt')
22
+ return File.read(options[:file] + '.srt')
23
+ elsif File.exists?(extensionless)
24
+ return File.read(extensionless)
25
+ end
26
+
3
27
  if false == "the file has subtitles embedded"
4
28
 
5
29
  else
@@ -8,8 +32,23 @@ class Storyboard
8
32
  # that it uses to call file.basename instead of File.basename(file),
9
33
  #but "file" has to be a "Path", so, whatever.
10
34
  suby_file = Path(options[:file])
11
- downloader = Suby::Downloader::OpenSubtitles.new(suby_file, 'en')
35
+ #downloader = Suby::Downloader::OpenSubtitles.new(suby_file, 'en')
36
+ # try Addic7ed first, as, on average, it seems a bit better.
37
+ downloader = nil
38
+ begin
39
+ LOG.debug("Searching for subtitles on Addic7ed")
40
+ #downloader = Suby::Downloader::Addic7ed.new(suby_file, 'en')
41
+ rescue Exception => e
42
+ LOG.debug(e)
43
+ end
44
+
45
+ if downloader.nil?
46
+ LOG.info("Searching for subtitles on OpenSubtitles")
47
+ downloader = Suby::Downloader::OpenSubtitles.new(suby_file, 'en')
48
+ end
49
+
12
50
  LOG.debug("Found #{downloader.download_url}")
51
+ #LOG.debug(downloader.found)
13
52
  downloader.extract(downloader.download_url)
14
53
  end
15
54
  end
@@ -37,8 +76,9 @@ class Storyboard
37
76
  page = nil
38
77
  @text.each_line {|l|
39
78
  l = l.strip
79
+ l = l.encode("UTF-32", :invalid=>:replace, :replace=>"?").encode("UTF-8")
40
80
  # Some files have BOM markers. Why? Why would you add a BOM marker.
41
- l.gsub!("\xEF\xBB\xBF".force_encoding("UTF-8"), '') if page.nil?
81
+ l.gsub!("\xEF\xBB\xBF", '') if page.nil?
42
82
  case phase
43
83
  when :line_no
44
84
  if l =~ /^\d+$/
@@ -60,7 +100,7 @@ class Storyboard
60
100
  phase = :line_no
61
101
  @pages << page
62
102
  else
63
- page[:lines] << l.gsub(%r{</?[^>]+?>}, '')
103
+ page[:lines] << l.gsub(/<\/?[^>]+?>/, '')
64
104
  end
65
105
  end
66
106
  }
@@ -1,3 +1,3 @@
1
1
  class Storyboard
2
- VERSION = "0.2.4"
2
+ VERSION = "0.3.0"
3
3
  end
data/storyboard.gemspec CHANGED
@@ -17,7 +17,7 @@ Gem::Specification.new do |gem|
17
17
  gem.version = Storyboard::VERSION
18
18
 
19
19
  gem.add_dependency 'nokogiri'
20
- gem.add_dependency 'rmagick'
20
+ gem.add_dependency 'mini_magick'
21
21
  gem.add_dependency 'prawn'
22
22
  gem.add_dependency 'ruby-progressbar'
23
23
  gem.add_dependency 'levenshtein-ffi'
@@ -28,28 +28,4 @@ Gem::Specification.new do |gem|
28
28
  gem.add_dependency 'term-ansicolor'
29
29
  gem.add_dependency 'mime-types', '>= 1.19'
30
30
 
31
- if File.exist?('.git')
32
- `git submodule --quiet foreach 'echo $path'`.split($\).each do |submodule_path|
33
- # for each submodule, change working directory to that submodule
34
- Dir.chdir(submodule_path) do
35
- # issue git ls-files in submodule's directory
36
- submodule_files = `git ls-files`.split($\)
37
-
38
-
39
- # prepend the submodule path to create absolute file paths
40
- submodule_files_fullpaths = submodule_files.map do |filename|
41
- "#{submodule_path}/#{filename}"
42
- end
43
-
44
- # remove leading path parts to get paths relative to the gem's root dir
45
- # (this assumes, that the gemspec resides in the gem's root dir)
46
- submodule_files_paths = submodule_files_fullpaths.map do |filename|
47
- filename.gsub "#{File.dirname(__FILE__)}/", ""
48
- end
49
-
50
- # add relative paths to gem.files
51
- gem.files += submodule_files_paths
52
- end
53
- end
54
- end
55
31
  end
@@ -12,7 +12,7 @@ module Suby
12
12
  DOWNLOADERS << downloader
13
13
  end
14
14
 
15
- attr_reader :show, :season, :episode, :video_data, :file, :lang
15
+ attr_reader :show, :season, :episode, :video_data, :file, :lang, :found
16
16
 
17
17
  def initialize(file, *args)
18
18
  @file = file
@@ -84,9 +84,9 @@ module Suby
84
84
  get(url_or_response)
85
85
  end
86
86
  end
87
-
87
+
88
88
  def save(contents)
89
- sub_name(contents).write
89
+ sub_name(contents).write
90
90
  end
91
91
 
92
92
  def extract(url_or_response)
@@ -14,7 +14,29 @@ module Suby
14
14
  FILTER_IGNORED = "Couldn't find any subs with the specified language. " +
15
15
  "Filter ignored"
16
16
 
17
+ # TODO - cache the shit out of this
17
18
  def subtitles_url
19
+ response = File.read('/Users/olson/Code/pdftv/shows.xml'); get("http://#{SITE}/ajax_getShows.php", {}, false)
20
+ series = {}
21
+ body = response.gsub(/<b>.*<\/b>/,'') #response.body.gsub(/<b>.*<\/b>/,'')
22
+ Nokogiri(body).css('option').each {|show|
23
+ series[show.inner_text.strip.downcase] = show['value'].to_i
24
+ }
25
+
26
+ potential_matches = [
27
+ @video_data[:show],
28
+ @video_data[:show].gsub(' & ', ' and '),
29
+ @video_data[:show].gsub(' and ', ' & '),
30
+ @video_data[:show].gsub('\'', '')
31
+ ]
32
+ found = nil
33
+ potential_matches.each{|name|
34
+ p series[name.downcase]
35
+ }
36
+ #print response.body
37
+ exit
38
+
39
+
18
40
  "/serie/#{CGI.escape show}/#{season}/#{episode}/#{LANG_IDS[lang]}"
19
41
  end
20
42
 
@@ -0,0 +1,7 @@
1
+ # http://www.addic7ed.com/ajax_getShows.php
2
+ # http://www.addic7ed.com/ajax_getSeasons.php?showID=SHOW_ID
3
+ # http://www.addic7ed.com/ajax_getEpisodes.php?showID=78&season=4
4
+
5
+ def find_show_id(title)
6
+
7
+ end
@@ -37,20 +37,9 @@ module Suby
37
37
  break subs
38
38
  end
39
39
  }
40
- x = s.select { |t| t['SeriesSeason'].to_i == @video_data[:season].to_i } if @video_data[:season]
41
- x.each {|t|
42
- puts t['MovieName'] + '/' + "\"#{@video_data[:show]}\" #{@video_data[:title]}" + " - " + Levenshtein.distance(t['MovieName'], "\"#{@video_data[:show]}\" #{@video_data[:title]}").to_i.to_s
43
- }
40
+ x = @video_data[:season] ? s.select { |t| t['SeriesSeason'].to_i == @video_data[:season].to_i } : s
44
41
  x.sort_by! { |t| Levenshtein.distance(t['MovieName'], "\"#{@video_data[:show]}\" #{@video_data[:title]}").to_i }
45
- p "|||||||||||||||"
46
- x.each {|t|
47
- puts t['MovieName'] + '/' + "\"#{@video_data[:show]}\" #{@video_data[:title]}" + " - " + Levenshtein.distance(t['MovieName'], "\"#{@video_data[:show]}\" #{@video_data[:title]}").to_i.to_s
48
- }
49
-
50
- p "======"
51
- p x.first
52
- p x.last
53
- p "-------"
42
+ @found = x.first
54
43
  x.first['SubDownloadLink']
55
44
  end
56
45
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: storyboard
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-15 00:00:00.000000000 Z
12
+ date: 2013-01-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: nokogiri
@@ -28,7 +28,7 @@ dependencies:
28
28
  - !ruby/object:Gem::Version
29
29
  version: '0'
30
30
  - !ruby/object:Gem::Dependency
31
- name: rmagick
31
+ name: mini_magick
32
32
  requirement: !ruby/object:Gem::Requirement
33
33
  none: false
34
34
  requirements:
@@ -160,7 +160,6 @@ email:
160
160
  - ! '"theothermarkolson@gmail.com"'
161
161
  executables:
162
162
  - storyboard
163
- - storyboard-ffprobe
164
163
  extensions: []
165
164
  extra_rdoc_files: []
166
165
  files:
@@ -168,12 +167,12 @@ files:
168
167
  - .rvmrc
169
168
  - Gemfile
170
169
  - Gemfile.lock
170
+ - INSTALL.md
171
171
  - README.md
172
- - TODO
173
172
  - bin/storyboard
174
- - bin/storyboard-ffprobe
175
173
  - lib/.DS_Store
176
174
  - lib/storyboard.rb
175
+ - lib/storyboard/bincheck.rb
177
176
  - lib/storyboard/generators/pdf.rb
178
177
  - lib/storyboard/generators/sub.rb
179
178
  - lib/storyboard/subtitles.rb
@@ -188,6 +187,7 @@ files:
188
187
  - vendor/suby/lib/suby.rb
189
188
  - vendor/suby/lib/suby/downloader.rb
190
189
  - vendor/suby/lib/suby/downloader/addic7ed.rb
190
+ - vendor/suby/lib/suby/downloader/addicted.rb
191
191
  - vendor/suby/lib/suby/downloader/opensubtitles.rb
192
192
  - vendor/suby/lib/suby/downloader/tvsubtitles.rb
193
193
  - vendor/suby/lib/suby/filename_parser.rb
@@ -224,7 +224,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
224
224
  version: '0'
225
225
  requirements: []
226
226
  rubyforge_project:
227
- rubygems_version: 1.8.24
227
+ rubygems_version: 1.8.23
228
228
  signing_key:
229
229
  specification_version: 3
230
230
  summary: Video to PDF/ePub generator
data/TODO DELETED
@@ -1,6 +0,0 @@
1
- epub/mobi geenerators - since mobi is generated from epub, should I just always make both?
2
- passing in a directory instead of a file
3
- error messages
4
- extract subtitles from the files
5
- imdb subtitles
6
- #{filename}.srt and #{File.basename(filename,".*")}.srt checks
Binary file