storyboard 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/.gitignore +3 -0
  2. data/.gitmodules +3 -0
  3. data/.rvmrc +1 -0
  4. data/Gemfile +10 -0
  5. data/Gemfile.lock +55 -0
  6. data/README.md +40 -0
  7. data/TODO +6 -0
  8. data/bin/storyboard +82 -0
  9. data/bin/storyboard-ffprobe +0 -0
  10. data/lib/.DS_Store +0 -0
  11. data/lib/storyboard/generators/pdf.rb +46 -0
  12. data/lib/storyboard/generators/sub.rb +32 -0
  13. data/lib/storyboard/subtitles.rb +96 -0
  14. data/lib/storyboard/thread-util.rb +308 -0
  15. data/lib/storyboard/time.rb +34 -0
  16. data/lib/storyboard/version.rb +3 -0
  17. data/lib/storyboard.rb +119 -0
  18. data/storyboard.gemspec +56 -0
  19. data/vendor/suby/.gitignore +3 -0
  20. data/vendor/suby/LICENSE +19 -0
  21. data/vendor/suby/README.md +27 -0
  22. data/vendor/suby/bin/suby +30 -0
  23. data/vendor/suby/lib/suby/downloader/addic7ed.rb +65 -0
  24. data/vendor/suby/lib/suby/downloader/opensubtitles.rb +83 -0
  25. data/vendor/suby/lib/suby/downloader/tvsubtitles.rb +90 -0
  26. data/vendor/suby/lib/suby/downloader.rb +177 -0
  27. data/vendor/suby/lib/suby/filename_parser.rb +103 -0
  28. data/vendor/suby/lib/suby/interface.rb +17 -0
  29. data/vendor/suby/lib/suby/movie_hasher.rb +31 -0
  30. data/vendor/suby/lib/suby.rb +89 -0
  31. data/vendor/suby/spec/fixtures/.gitkeep +0 -0
  32. data/vendor/suby/spec/mock_http.rb +22 -0
  33. data/vendor/suby/spec/spec_helper.rb +3 -0
  34. data/vendor/suby/spec/suby/downloader/addict7ed_spec.rb +28 -0
  35. data/vendor/suby/spec/suby/downloader/opensubtitles_spec.rb +33 -0
  36. data/vendor/suby/spec/suby/downloader/tvsubtitles_spec.rb +50 -0
  37. data/vendor/suby/spec/suby/downloader_spec.rb +11 -0
  38. data/vendor/suby/spec/suby/filename_parser_spec.rb +66 -0
  39. data/vendor/suby/spec/suby_spec.rb +27 -0
  40. data/vendor/suby/suby.gemspec +20 -0
  41. metadata +232 -0
@@ -0,0 +1,177 @@
1
+ require 'net/http'
2
+ require 'cgi/util'
3
+ require 'nokogiri'
4
+ require 'xmlrpc/client'
5
+ require 'zlib'
6
+ require 'stringio'
7
+
8
+ module Suby
9
+ class Downloader
10
+ DOWNLOADERS = []
11
+ def self.inherited(downloader)
12
+ DOWNLOADERS << downloader
13
+ end
14
+
15
+ attr_reader :show, :season, :episode, :video_data, :file, :lang
16
+
17
+ def initialize(file, *args)
18
+ @file = file
19
+ @lang = (args.last || 'en').to_sym
20
+ @video_data = FilenameParser.parse(file)
21
+ if video_data[:type] == :tvshow
22
+ @show, @season, @episode = video_data.values_at(:show, :season, :episode)
23
+ end
24
+ end
25
+
26
+ def support_video_type?
27
+ self.class::SUBTITLE_TYPES.include? video_data[:type]
28
+ end
29
+
30
+ def to_s
31
+ self.class.name.sub(/^.+::/, '')
32
+ end
33
+
34
+ def http
35
+ @http ||= Net::HTTP.new(self.class::SITE).start
36
+ end
37
+
38
+ def xmlrpc
39
+ @xmlrpc ||= XMLRPC::Client.new(self.class::SITE, self.class::XMLRPC_PATH)
40
+ end
41
+
42
+ def get(path, initheader = {}, parse_response = true)
43
+ response = http.get(path, initheader)
44
+ if parse_response
45
+ unless Net::HTTPSuccess === response
46
+ raise DownloaderError, "Invalid response for #{path}: #{response}"
47
+ end
48
+ response.body
49
+ else
50
+ response
51
+ end
52
+ end
53
+
54
+ def post(path, data = {}, initheader = {})
55
+ post = Net::HTTP::Post.new(path, initheader)
56
+ post.form_data = data
57
+ response = http.request(post)
58
+ unless Net::HTTPSuccess === response
59
+ raise DownloaderError, "Invalid response for #{path}(#{data}): " +
60
+ response.inspect
61
+ end
62
+ response.body
63
+ end
64
+
65
+ def get_redirection(path, initheader = {})
66
+ response = http.get(path, initheader)
67
+ location = response['Location']
68
+ unless (Net::HTTPFound === response or
69
+ Net::HTTPSuccess === response) and location
70
+ raise DownloaderError, "Invalid response for #{path}: " +
71
+ "#{response}: location: #{location.inspect}, #{response.body}"
72
+ end
73
+ location
74
+ end
75
+
76
+ def download
77
+ save extract download_url
78
+ end
79
+
80
+ def subtitles(url_or_response = download_url)
81
+ if Net::HTTPSuccess === url_or_response
82
+ url_or_response.body
83
+ else
84
+ get(url_or_response)
85
+ end
86
+ end
87
+
88
+ def save(contents)
89
+ sub_name(contents).write
90
+ end
91
+
92
+ def extract(url_or_response)
93
+ contents = subtitles(url_or_response)
94
+ http.finish
95
+ format = self.class::FORMAT
96
+ case format
97
+ when :file
98
+ # nothing special to do
99
+ when :gz
100
+ begin
101
+ gz = Zlib::GzipReader.new(StringIO.new(contents))
102
+ contents = gz.read
103
+ ensure
104
+ gz.close if gz
105
+ end
106
+ when :zip
107
+ TEMP_ARCHIVE.write contents
108
+ Suby.extract_sub_from_archive(TEMP_ARCHIVE, format, TEMP_SUBTITLES)
109
+ contents = TEMP_SUBTITLES.read
110
+ else
111
+ raise "unknown subtitles format: #{format}"
112
+ end
113
+ encode contents
114
+ end
115
+
116
+ def sub_name(contents)
117
+ file.sub_ext sub_extension(contents)
118
+ end
119
+
120
+ def sub_extension(contents)
121
+ if contents[0..10] =~ /1\r?\n/
122
+ 'srt'
123
+ else
124
+ 'sub'
125
+ end
126
+ end
127
+
128
+ def imdbid
129
+ @imdbid ||= begin
130
+ nfo_file = find_nfo_file
131
+ convert_to_utf8_from_latin1(nfo_file.read)[%r!imdb\.[^/]+/title/tt(\d+)!i, 1] if nfo_file
132
+ end
133
+ end
134
+
135
+ def find_nfo_file
136
+ @file.dir.children.find { |file| file.ext == "nfo" }
137
+ end
138
+
139
+ def convert_to_utf8_from_latin1(content)
140
+ if content.valid_encoding?
141
+ content
142
+ else
143
+ enc = content.encoding
144
+ if content.force_encoding("ISO-8859-1").valid_encoding?
145
+ yield if block_given?
146
+ content.encode("UTF-8")
147
+ else
148
+ # restore original encoding
149
+ subtitles.force_encoding(enc)
150
+ end
151
+ end
152
+ end
153
+
154
+ def success_message
155
+ "Found"
156
+ end
157
+
158
+ def encode(subtitles)
159
+ if @lang == :fr
160
+ convert_to_utf8_from_latin1(subtitles) do
161
+ def self.success_message
162
+ "#{super} (transcoded from ISO-8859-1)"
163
+ end
164
+ end
165
+ else
166
+ subtitles
167
+ end
168
+ end
169
+ end
170
+ end
171
+
172
+ # Defines downloader order
173
+ %w[
174
+ opensubtitles
175
+ tvsubtitles
176
+ addic7ed
177
+ ].each { |downloader| require_relative "downloader/#{downloader}" }
@@ -0,0 +1,103 @@
1
+ module Suby
2
+ module FilenameParser
3
+ extend self
4
+
5
+ # from tvnamer @ ab2c6c, with author's agreement, adapted
6
+ # See https://github.com/dbr/tvnamer/blob/master/tvnamer/config_defaults.py
7
+ TVSHOW_PATTERNS = [
8
+ # foo.s0101
9
+ /^(?<show>.+?)
10
+ [ \._\-]
11
+ [Ss](?<season>[0-9]{2})
12
+ [\.\- ]?
13
+ (?<episode>[0-9]{2})
14
+ [^0-9]*$/x,
15
+
16
+ # foo.1x09*
17
+ /^(?<show>.+?)
18
+ [ \._\-]
19
+ \[?
20
+ (?<season>[0-9]+)
21
+ [xX]
22
+ (?<episode>[0-9]+)
23
+ \]?
24
+ [^\/]*$/x,
25
+
26
+ # foo.s01.e01, foo.s01_e01
27
+ /^(?<show>.+?)
28
+ [ \._\-]
29
+ \[?
30
+ [Ss](?<season>[0-9]+)[\. _-]?
31
+ [Ee]?(?<episode>[0-9]+)
32
+ \]?
33
+ [^\/]*$/x,
34
+
35
+ # foo - [01.09]
36
+ /^(?<show>.+?)
37
+ [ \._\-]?
38
+ \[
39
+ (?<season>[0-9]+?)
40
+ [.]
41
+ (?<episode>[0-9]+?)
42
+ \]
43
+ [ \._\-]?
44
+ [^\/]*$/x,
45
+
46
+ # Foo - S2 E 02 - etc
47
+ /^(?<show>.+?)
48
+ [ ]?[ \._\-][ ]?
49
+ [Ss](?<season>[0-9]+)[\.\- ]?
50
+ [Ee]?[ ]?(?<episode>[0-9]+)
51
+ [^\/]*$/x,
52
+
53
+ # Show - Episode 9999 [S 12 - Ep 131] - etc
54
+ /(?<show>.+)
55
+ [ ]-[ ]
56
+ [Ee]pisode[ ]\d+
57
+ [ ]
58
+ \[
59
+ [sS][ ]?(?<season>\d+)
60
+ ([ ]|[ ]-[ ]|-)
61
+ ([eE]|[eE]p)[ ]?(?<episode>\d+)
62
+ \]
63
+ .*$/x,
64
+
65
+ # foo.103*
66
+ /^(?<show>.+)
67
+ [ \._\-]
68
+ (?<season>[0-9]{1})
69
+ (?<episode>[0-9]{2})
70
+ [\._ -][^\/]*$/x,
71
+ ]
72
+ MOVIE_PATTERN = /^(?<movie>.*)[.\[( ](?<year>(?:19|20)\d{2})/
73
+
74
+ def parse(file)
75
+ filename = file.basename.to_s
76
+ if TVSHOW_PATTERNS.find { |pattern| pattern.match(filename) }
77
+ m = $~
78
+ { type: :tvshow, show: clean_show_name(m[:show]), season: m[:season].to_i, episode: m[:episode].to_i }
79
+ elsif m = MOVIE_PATTERN.match(filename)
80
+ { type: :movie, name: clean_show_name(m[:movie]), year: m[:year].to_i }
81
+ else
82
+ { type: :unknown, name: filename }
83
+ end
84
+ end
85
+
86
+ # from https://github.com/dbr/tvnamer/blob/master/tvnamer/utils.py#L78-95
87
+ # Cleans up series name by removing any . and _
88
+ # characters, along with any trailing hyphens.
89
+ #
90
+ # Is basically equivalent to replacing all _ and . with a
91
+ # space, but handles decimal numbers in string.
92
+ #
93
+ # clean_show_name("an.example.1.0.test") # => "an example 1.0 test"
94
+ # clean_show_name("an_example_1.0_test") # => "an example 1.0 test"
95
+ def clean_show_name show
96
+ show.gsub!(/(?<!\d)[.]|[.](?!\d)/, ' ')
97
+ show.tr!('_', ' ')
98
+ show.chomp!('-')
99
+ show.strip!
100
+ show
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,17 @@
1
+ require 'term/ansicolor'
2
+
3
+ module Suby
4
+ module Interface
5
+ def success message
6
+ puts Term::ANSIColor.green message
7
+ end
8
+
9
+ def failure message
10
+ puts Term::ANSIColor.blue message
11
+ end
12
+
13
+ def error message
14
+ puts Term::ANSIColor.red message
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,31 @@
1
+ module Suby
2
+ # from http://trac.opensubtitles.org/projects/opensubtitles/wiki/HashSourceCodes
3
+ module MovieHasher
4
+
5
+ CHUNK_SIZE = 64 * 1024 # in bytes
6
+ MASK64 = 0xffffffffffffffff # 2^64 - 1
7
+
8
+ def self.compute_hash(file)
9
+ filesize = file.size
10
+ hash = filesize
11
+
12
+ # Read 64 kbytes, divide up into 64 bits and add each
13
+ # to hash. Do for beginning and end of file.
14
+ file.open('rb') do |f|
15
+ # Q = unsigned long long = 64 bit
16
+ f.read(CHUNK_SIZE).unpack("Q*").each do |n|
17
+ hash = (hash + n) & MASK64
18
+ end
19
+
20
+ f.seek([0, filesize - CHUNK_SIZE].max, IO::SEEK_SET)
21
+
22
+ # And again for the end of the file
23
+ f.read(CHUNK_SIZE).unpack("Q*").each do |n|
24
+ hash = (hash + n) & MASK64
25
+ end
26
+ end
27
+
28
+ "%016x" % hash
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,89 @@
1
+ require 'path'
2
+ require 'zip/zip'
3
+ require 'mime/types'
4
+
5
+ Path.require_tree 'suby', except: %w[downloader/]
6
+
7
+ module Suby
8
+ NotFoundError = Class.new StandardError
9
+ DownloaderError = Class.new StandardError
10
+
11
+ SUB_EXTENSIONS = %w[srt sub]
12
+ TMPDIR = Path.tmpdir
13
+ TEMP_ARCHIVE = TMPDIR / 'archive'
14
+ TEMP_SUBTITLES = TMPDIR / 'subtitles'
15
+
16
+ class << self
17
+ include Interface
18
+
19
+ def download_subtitles(files, options = {})
20
+ Zip.options[:on_exists_proc] = options[:force]
21
+ files.each { |file|
22
+ file = Path(file)
23
+ if file.dir?
24
+ download_subtitles(file.children, options)
25
+ elsif SUB_EXTENSIONS.include?(file.ext)
26
+ # ignore already downloaded subtitles
27
+ elsif !options[:force] and SUB_EXTENSIONS.any? { |ext| f = file.sub_ext(ext) and f.exist? and !f.empty? }
28
+ puts "Skipping: #{file}"
29
+ elsif !file.exist? or video?(file)
30
+ download_subtitles_for_file(file, options)
31
+ end
32
+ }
33
+ ensure
34
+ TMPDIR.rm_rf
35
+ end
36
+
37
+ def video?(file)
38
+ MIME::Types.type_for(file.path).any? { |type| type.media_type == "video" }
39
+ end
40
+
41
+ def download_subtitles_for_file(file, options)
42
+ begin
43
+ puts file
44
+ success = Downloader::DOWNLOADERS.find { |downloader_class|
45
+ try_downloader(downloader_class.new(file, options[:lang]))
46
+ }
47
+ error "\nNo downloader could find subtitles for #{file}" unless success
48
+ rescue
49
+ error "\nThe download of the subtitles failed for #{file}:"
50
+ error "#{$!.class}: #{$!.message}"
51
+ $stderr.puts $!.backtrace
52
+ end
53
+ end
54
+
55
+ def try_downloader(downloader)
56
+ return false unless downloader.support_video_type?
57
+ begin
58
+ print " #{downloader.to_s.ljust(20)}"
59
+ downloader.download
60
+ rescue Suby::NotFoundError => error
61
+ failure "Failed: #{error.message}"
62
+ false
63
+ rescue Suby::DownloaderError => error
64
+ error "Error: #{error.message}"
65
+ false
66
+ else
67
+ success downloader.success_message
68
+ true
69
+ end
70
+ end
71
+
72
+ def extract_sub_from_archive(archive, format, file)
73
+ case format
74
+ when :zip
75
+ Zip::ZipFile.open(archive.to_s) { |zip|
76
+ sub = zip.entries.find { |entry|
77
+ entry.to_s =~ /\.#{Regexp.union SUB_EXTENSIONS}$/
78
+ }
79
+ raise "no subtitles in #{archive}" unless sub
80
+ sub.extract(file.to_s)
81
+ }
82
+ else
83
+ raise "unknown archive type (#{archive})"
84
+ end
85
+ ensure
86
+ archive.unlink if archive.exist?
87
+ end
88
+ end
89
+ end
File without changes
@@ -0,0 +1,22 @@
1
+ class Suby::Downloader
2
+ caches = {}
3
+ [:get, :post, :get_redirection].each { |meth|
4
+ original_method = instance_method(meth)
5
+ remove_method meth
6
+ define_method(meth) { |*args|
7
+ file = 'spec/fixtures/' + self.class::SITE.downcase + '.marshal'
8
+ caches[file] ||= File.exist?(file) ? Marshal.load(IO.read(file)) : {}
9
+ data = caches[file]
10
+
11
+ if data[args]
12
+ data[args]
13
+ else
14
+ puts "doing the real request: #{meth}(#{args * ', '})"
15
+ value = original_method.bind(self).call(*args)
16
+ data[args] = value
17
+ File.write(file, Marshal.dump(data))
18
+ value
19
+ end
20
+ }
21
+ }
22
+ end
@@ -0,0 +1,3 @@
1
+ require 'rspec'
2
+ require_relative '../lib/suby'
3
+ require_relative 'mock_http'
@@ -0,0 +1,28 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe Suby::Downloader::Addic7ed do
4
+ file = Path('The Glee Project 01x03.avi')
5
+ downloader = Suby::Downloader::Addic7ed.new file
6
+
7
+ it 'finds the right subtitles' do
8
+ begin
9
+ downloader.subtitles[0..100].should include "Ellis, best first kiss?"
10
+ rescue Suby::NotFoundError => e
11
+ if e.message == "download exceeded"
12
+ pending e.message
13
+ else
14
+ raise e
15
+ end
16
+ end
17
+ end
18
+
19
+ it 'fails gently when the show or the episode does not exist' do
20
+ d = Suby::Downloader::Addic7ed.new(Path('Not Existing Show 1x1.mkv'))
21
+ -> { d.download_url }.should raise_error(Suby::NotFoundError, "show/season/episode not found")
22
+ end
23
+
24
+ it 'fails gently when there is no subtitles available' do
25
+ d = Suby::Downloader::Addic7ed.new(file, :es)
26
+ -> { p d.download_url }.should raise_error(Suby::NotFoundError, "no subtitles available")
27
+ end
28
+ end
@@ -0,0 +1,33 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe Suby::Downloader::OpenSubtitles do
4
+ file = Path("breaking.bad.s05e04.hdtv.x264-fqm.mp4")
5
+ downloader = Suby::Downloader::OpenSubtitles.new file
6
+ correct_query = [{ moviehash: "709b9ff887cf987d", moviebytesize: "308412149", sublanguageid: "eng" }]
7
+ wrong_query = correct_query.first.merge({ sublanguageid: "wrong_language" })
8
+
9
+ it 'finds the right subtitles' do
10
+ response = downloader.search_subtitles(correct_query)['data']
11
+ response.should_not be_false
12
+ response.first['MovieName'].should == '"Breaking Bad" Fifty-One'
13
+ end
14
+
15
+ it 'finds the right download link' do
16
+ url = downloader.download_url
17
+ url.should match(%r{http(s)?://.*opensubtitles.org/en/download/.*})
18
+ end
19
+
20
+ it "doesn't find anything for bad query" do
21
+ response = downloader.search_subtitles(wrong_query)['data']
22
+ response.should be_false
23
+ end
24
+
25
+ it "gets right token" do
26
+ downloader.token.should match(/\A[a-z0-9]{26}\z/)
27
+ end
28
+
29
+ it 'fails gently when there is no subtitles available' do
30
+ d = Suby::Downloader::OpenSubtitles.new(Path("Not Existing Show 1x1.mkv"), :eawdad)
31
+ -> { d.download_url }.should raise_error(Suby::NotFoundError, "no subtitles available")
32
+ end
33
+ end
@@ -0,0 +1,50 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe Suby::Downloader::TVSubtitles do
4
+ file = Path('How I Met Your Mother 3x9 - Slapsgiving.mkv')
5
+ downloader = Suby::Downloader::TVSubtitles.new(file)
6
+ downloader_fr = Suby::Downloader::TVSubtitles.new(file, :fr)
7
+
8
+ it 'finds the right show url' do
9
+ downloader.show_url.should == '/tvshow-110.html'
10
+ end
11
+
12
+ it 'finds the right season url' do
13
+ downloader.season_url.should == '/tvshow-110-3.html'
14
+ end
15
+
16
+ it 'finds the right episode url' do
17
+ downloader.episode_url.should == '/episode-7517-en.html'
18
+ downloader_fr.episode_url.should == '/episode-7517-fr.html'
19
+ end
20
+
21
+ it 'finds the right subtitles url' do
22
+ downloader.subtitles_url.should == '/subtitle-9339.html'
23
+ downloader_fr.subtitles_url.should == '/subtitle-31249.html'
24
+ end
25
+
26
+ it 'finds the right download url' do
27
+ downloader.download_url.should == '/files/How%20I%20Met%20Your%20Mother_3x09_en.zip'
28
+ downloader_fr.download_url.should == '/files/How%20I%20Met%20Your%20Mother_3x09_fr.zip'
29
+ end
30
+
31
+ it 'fails gently when the show does not exist' do
32
+ d = Suby::Downloader::TVSubtitles.new(Path('Not Existing Show 1x1.mkv'))
33
+ -> { d.show_url }.should raise_error(Suby::NotFoundError, "show not found")
34
+ end
35
+
36
+ it 'fails gently when the season does not exist' do
37
+ d = Suby::Downloader::TVSubtitles.new(Path('How I Met Your Mother 99x1.mkv'))
38
+ -> { d.episode_url }.should raise_error(Suby::NotFoundError, "season not found")
39
+ end
40
+
41
+ it 'fails gently when the episode does not exist' do
42
+ d = Suby::Downloader::TVSubtitles.new(Path('How I Met Your Mother 3x99.mkv'))
43
+ -> { d.episode_url }.should raise_error(Suby::NotFoundError, "episode not found")
44
+ end
45
+
46
+ it 'fails gently when there is no subtitles available' do
47
+ d = Suby::Downloader::TVSubtitles.new(Path('Batman: The Animated Series 1x03.mkv'))
48
+ -> { d.subtitles_url }.should raise_error(Suby::NotFoundError, "no subtitles available")
49
+ end
50
+ end
@@ -0,0 +1,11 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe Suby::Downloader do
4
+ downloader = Suby::Downloader.new Path('How I Met Your Mother 3x9 - Slapsgiving.mkv')
5
+ it 'guess the right type of subtitles from the contents' do
6
+ downloader.sub_extension("1\r\n00").should == 'srt'
7
+ downloader.sub_extension("\xEF\xBB\xBF1\r\n00:00:14,397").should == 'srt'
8
+ downloader.sub_extension("\xEF\xBB\xBF1\r\n00:00:14,397").should == 'srt'
9
+ downloader.sub_extension("{346}{417}informa").should == 'sub'
10
+ end
11
+ end
@@ -0,0 +1,66 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe Suby::Downloader do
4
+ show = 'How I Met Your Mother'
5
+ season, episode = 3, 9
6
+ title = 'Slapsgiving'
7
+ ext = 'mkv'
8
+ dot_show = show.tr(' ', '.')
9
+ und_show = show.tr(' ', '_')
10
+ movie_name = "Somemovie.2002.720p.BluRay"
11
+ unknown_name = "crf-hp4"
12
+
13
+ context "cleans correctly the show name" do
14
+ {
15
+ dot_show => show,
16
+ und_show => show,
17
+ "an.example.1.0.test" => "an example 1.0 test",
18
+ "an_example_1.0_test" => "an example 1.0 test",
19
+ "an_3.0.1.example_1.0_test" => "an 3.0.1 example 1.0 test",
20
+ }.each_pair { |raw_show, true_show|
21
+ it raw_show do
22
+ # dup because a literal String is frozen and no point to keep the raw show
23
+ Suby::FilenameParser.clean_show_name(raw_show.dup).should == true_show
24
+ end
25
+ }
26
+ end
27
+
28
+ context "parse correctly the file name" do
29
+ [
30
+ {
31
+ examples:
32
+ [
33
+ "#{show} #{season}x#{episode}",
34
+ "#{show} #{season}x#{"%.2d" % episode}",
35
+ "#{show} #{season}x#{episode} - #{title}",
36
+ "#{show} #{season}x#{"%.2d" % episode} - #{title}",
37
+ "#{dot_show}.s0309",
38
+ "#{dot_show}.3x09",
39
+ "#{dot_show}.s03.e09",
40
+ "#{und_show}.s03_e09",
41
+ "#{show} - [03.09]",
42
+ "#{show} - S3 E 09",
43
+ "#{show} - Episode 9999 [S 3 - Ep 9]",
44
+ "#{show} - Episode 9999 [S 3 - Ep 9] - ",
45
+ "#{dot_show}.309",
46
+ ],
47
+ expected: { type: :tvshow, show: show, season: season, episode: episode }
48
+ },
49
+ {
50
+ examples: [movie_name],
51
+ expected: { type: :movie, name: "Somemovie", year: 2002 }
52
+ },
53
+ {
54
+ examples: [unknown_name],
55
+ expected: { type: :unknown, name: "#{unknown_name}.#{ext}"}
56
+ }
57
+ ].each do |type|
58
+ type[:examples].each do |filename|
59
+ it filename do
60
+ file = Path(filename).add_ext(ext)
61
+ Suby::FilenameParser.parse(file).should == type[:expected]
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,27 @@
1
+ require_relative 'spec_helper'
2
+ require 'tmpdir'
3
+ require 'digest/md5'
4
+
5
+ describe Suby do
6
+ file = 'How I Met Your Mother 3x9 - Slapsgiving.mkv'
7
+ srt = 'How I Met Your Mother 3x9 - Slapsgiving.srt'
8
+
9
+ it 'works :D', full: true do
10
+ Dir.mktmpdir do |dir|
11
+ suby = File.expand_path('../../bin/suby', __FILE__)
12
+ Dir.chdir(dir) do
13
+ system suby, file
14
+ Digest::MD5.hexdigest(File.read(srt)).should == '7c4b89452782c20c6086ba5c1f4e9d74'
15
+ end
16
+ end
17
+ end
18
+
19
+ it 'can detect videos' do
20
+ %w[avi mp4 mkv].each { |ext|
21
+ Suby.should be_a_video(Path("file").add_ext(ext))
22
+ }
23
+ %w[txt srt sub].each { |ext|
24
+ Suby.should_not be_a_video(Path("file").add_ext(ext))
25
+ }
26
+ end
27
+ end
@@ -0,0 +1,20 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'suby'
3
+ s.summary = "Subtitles' downloader"
4
+ s.description = "Find and download subtitles"
5
+ s.author = 'eregon'
6
+ s.email = 'eregontp@gmail.com'
7
+ s.homepage = 'https://github.com/eregon/suby'
8
+
9
+ s.files = Dir['bin/*', 'lib/**/*.rb', '.gitignore', 'README.md', 'suby.gemspec']
10
+ s.executables = ['suby']
11
+
12
+ s.required_ruby_version = '>= 1.9.2'
13
+ s.add_dependency 'path', '>= 1.3.0'
14
+ s.add_dependency 'nokogiri'
15
+ s.add_dependency 'rubyzip'
16
+ s.add_dependency 'term-ansicolor'
17
+ s.add_dependency 'mime-types', '>= 1.19'
18
+
19
+ s.version = '0.4.0'
20
+ end