osdb 0.0.9 → 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.travis.yml ADDED
@@ -0,0 +1,9 @@
1
+ rvm:
2
+ - 1.8.7 # (current default)
3
+ - 1.9.2
4
+ - 1.9.3
5
+ - rbx
6
+ - jruby
7
+ - ruby-head
8
+ - ree
9
+
data/README.md CHANGED
@@ -3,6 +3,8 @@
3
3
  Client library for the [OSDb protocol](http://trac.opensubtitles.org/projects/opensubtitles/wiki/XMLRPC).
4
4
  Currently the implentation is limited to movie identification and subtitles search
5
5
 
6
+ [![Build Status](https://secure.travis-ci.org/byroot/ruby-osdb.png)](http://travis-ci.org/byroot/ruby-osdb)
7
+
6
8
  ## Examples
7
9
 
8
10
  Just read the source of `bin/getsub` it is a typical example of OSDb's capacities.
data/bin/getsub CHANGED
@@ -16,16 +16,23 @@ end
16
16
  opts.separator "Usage: getsub [options] DIRECTORY | VIDEO_FILE [VIDEO_FILE ...]"
17
17
  opts.separator ""
18
18
  opts.separator "Main options:"
19
-
20
- opts.on("-l", "--language LANGUAGE", "Sub language ISO 963 code like fre or eng. Default: env $LANG (#{env_lang.to_iso639_2b})") do |language|
21
- @options[:language] = language
19
+
20
+ opts.on("-l", "--language LANGUAGE", "Sub language ISO 639-2 code like fre or eng. Default: env $LANG (#{env_lang.to_iso639_2b})") do |language|
21
+ if language.to_s.length != 3
22
+ STDERR.puts "Language should specified as ISO 639-2 (ie, 3 letters, like 'eng' or 'fre')"
23
+ exit 1
24
+ end
25
+ @options[:language] = language.to_s
22
26
  end
23
-
27
+
24
28
  opts.on("-d", "--directory DIRECTORY", "Specify a directory to search recursively for movies") do |dir|
25
29
  @options[:dir] = dir
26
30
  end
27
31
 
28
32
  opts.on("-f", "--force", "Download sub even if video already has one") { @options[:force] = true }
33
+
34
+ opts.on("-t", "--type FORMATS", "Select only subtitles in specified formats. e.g -t srt,sub") { |formats| @options[:formats] = formats.to_s.split(',') }
35
+
29
36
  end
30
37
  @parser.parse!
31
38
 
@@ -66,44 +73,34 @@ def ask_user_to_identify_movie(movies)
66
73
  print 'id: '
67
74
  str = STDIN.gets # TODO: rule #1, never trust user input
68
75
  puts
69
- movies[movies.keys[str.to_i]]
76
+ movies[movies.keys[str.to_i]] || []
70
77
  end
71
78
 
72
- def identify_by_imdb!(server, movie)
73
- puts "* could not find sub by hash, trying IMDB"
74
- imdb_results = server.search_imdb(:query => movie.name)
75
- if imdb_results.any?
76
- if imdb_results.length == 1
77
- imdb_result = imdb_results.first
78
- puts "* found on IMDB with ID: #{imdb_result.imdbid}"
79
- else
80
- movies = Hash[imdb_results.map{ |r| [r.title, r] }]
81
- imdb_result = ask_user_to_identify_movie(movies)
82
- end
83
- subs = server.search_subtitles(:sublanguageid => @options[:language], :imdbid => imdb_result.imdbid)
84
- if subs.any?
85
- select_and_download!(subs, movie)
86
- else
87
- puts "* no sub found for this movie"
88
- end
89
- else
90
- puts "* no movie found on IMDB"
91
- end
79
+ def normalize_name(name)
80
+ name.downcase.gsub(/[\s\.\-\_]+/, ' ')
92
81
  end
93
82
 
94
- def select_sub(subs)
95
- return subs.first if subs.length >= 1
96
- movies = group_by_movie_name(subs)
97
- return movies.values.first.max if movies.length == 1
83
+ def select_movie(movies)
84
+ return movies.values.first || [] if movies.length <= 1
98
85
 
99
86
  puts "D'oh! You stumbled upon a hash conflict, please resolve it:"
100
87
  puts
101
- selected_movie_subs = ask_user_to_identify_movie(movies)
102
- selected_movie_subs.max
88
+ ask_user_to_identify_movie(movies)
89
+ end
90
+
91
+ def select_format(subs)
92
+ return subs unless @options[:formats]
93
+ subs.select{ |s| @options[:formats].include?(s.format) }
94
+ end
95
+
96
+ def select_sub(subs)
97
+ subs = select_format(subs)
98
+ movies = group_by_movie_name(subs)
99
+ subs = select_movie(movies)
100
+ subs.max_by(&:score)
103
101
  end
104
102
 
105
- def select_and_download!(subs, movie)
106
- sub = select_sub(subs)
103
+ def download_sub!(sub, movie)
107
104
  sub_path = movie.sub_path(sub.format)
108
105
  download!(sub.url, sub_path)
109
106
  end
@@ -130,17 +127,70 @@ if movies.empty?
130
127
  exit 1
131
128
  end
132
129
 
130
+ def search_by_hash(server, movie)
131
+ server.search_subtitles(:moviehash => movie.hash, :moviebytesize => movie.size.to_s, :sublanguageid => @options[:language])
132
+ end
133
+
134
+ def search_by_path(server, movie)
135
+ server.search_subtitles(:sublanguageid => @options[:language], :tag => movie.path)
136
+ end
137
+
138
+ def search_by_name(server, movie)
139
+ subs = server.search_subtitles(:sublanguageid => @options[:language], :query => movie.name)
140
+ normalized_movie_name = normalize_name(movie.name)
141
+ subs.select! do |sub|
142
+ normalize_name(sub.filename).index(normalized_movie_name) # MAYBE: Levenshtein ?
143
+ end
144
+ subs if subs.any?
145
+ end
146
+
147
+ def search_by_imdb(server, movie)
148
+ imdb_results = server.search_imdb(:query => movie.name)
149
+ if imdb_results.any?
150
+ if imdb_results.length == 1
151
+ imdb_result = imdb_results.first
152
+ puts "* found on IMDB with ID: #{imdb_result.imdbid}"
153
+ else
154
+ movies = Hash[imdb_results.map{ |r| [r.title, r] }]
155
+ imdb_result = ask_user_to_identify_movie(movies)
156
+ end
157
+ server.search_subtitles(:sublanguageid => @options[:language], :imdbid => imdb_result.imdbid)
158
+ end
159
+ end
160
+
133
161
  movies.each do |movie|
134
162
  begin
135
- puts "* search subs for: #{movie.path}"
136
- subs = server.search_subtitles(:moviehash => movie.hash, :moviebytesize => movie.size.to_s, :sublanguageid => @options[:language])
137
- if subs.any?
138
- select_and_download!(subs, movie)
163
+ puts "* search subs by hash for: #{movie.path}"
164
+ sub = select_sub search_by_hash(server, movie)
165
+
166
+ unless sub
167
+ puts "* could not find sub by hash, trying IMDB"
168
+ sub = select_sub search_by_imdb(server, movie)
169
+ end
170
+
171
+ unless sub
172
+ puts "* no matches"
173
+ puts "* search subs by path"
174
+ sub = select_sub search_by_path(server, movie)
175
+ end
176
+
177
+ unless sub
178
+ puts "* still no matches"
179
+ puts "* search subs by filename"
180
+ sub = select_sub search_by_name(server, movie)
181
+ end
182
+
183
+ if sub
184
+ download_sub!(sub, movie)
139
185
  else
140
- identify_by_imdb!(server, movie)
186
+ puts "Nothing worked, you are very unlucky :'("
141
187
  end
142
188
  puts
143
189
  rescue Exception => e
190
+ puts "Something crashed."
191
+ puts "Feel free to report the error here: https://github.com/byroot/ruby-osdb/issues"
192
+ puts "With the following debug informations:"
193
+ puts
144
194
  puts "#{e.class.name}: #{e.message}:"
145
195
  puts e.backtrace
146
196
  end
data/lib/osdb/sub.rb CHANGED
@@ -1,24 +1,40 @@
1
1
  require 'uri'
2
2
 
3
3
  module OSDb
4
-
4
+
5
5
  class Sub
6
-
7
- attr_reader :url, :format, :language, :rating, :movie_name, :raw_data
8
-
6
+
7
+ attr_reader :url, :format, :language, :rating, :user_ranks, :movie_name,
8
+ :filename, :raw_data, :downloads_count, :bad_reports_count
9
+
9
10
  def initialize(data)
10
11
  @url = URI.parse(data['SubDownloadLink'])
11
12
  @format = data['SubFormat']
12
13
  @language = Language.from_iso639_2b(data['SubLanguageID'])
13
14
  @rating = data['SubRating'].to_f
15
+ @user_ranks = data['UserRank']
14
16
  @movie_name = data['MovieName']
17
+ @filename = data['SubFileName']
18
+ @downloads_count = data['SubDownloadsCnt'].to_i
19
+ @bad_reports_count = data['SubBad'].to_i
15
20
  @raw_data = data
16
21
  end
17
-
22
+
18
23
  def <=>(other)
19
24
  rating <=> other.rating
20
25
  end
21
-
26
+
27
+ # Totaly subjective formula to evaluate subtitle quality
28
+ # Originaly developed by runa (https://github.com/runa)
29
+ # https://github.com/byroot/ruby-osdb/commit/9d71775#L0R122
30
+ def score
31
+ uploader_score * downloads_count.next * (rating + 1) - bad_reports_count / downloads_count.next
32
+ end
33
+
34
+ def uploader_score
35
+ user_ranks.empty? ? 1 : 2
36
+ end
37
+
22
38
  end
23
-
24
- end
39
+
40
+ end
data/lib/osdb/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module OSDb
2
- VERSION = '0.0.9'
2
+ VERSION = '0.0.10'
3
3
  end
data/osdb.gemspec CHANGED
@@ -17,5 +17,6 @@ Gem::Specification.new do |s|
17
17
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
18
  s.require_paths = ["lib"]
19
19
 
20
+ s.add_development_dependency 'rake'
20
21
  s.add_development_dependency 'rspec'
21
22
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: osdb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.0.10
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,22 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-12 00:00:00.000000000 Z
12
+ date: 2012-08-26 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: &70311392052000 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70311392052000
14
25
  - !ruby/object:Gem::Dependency
15
26
  name: rspec
16
- requirement: &70099189686620 !ruby/object:Gem::Requirement
27
+ requirement: &70311392067940 !ruby/object:Gem::Requirement
17
28
  none: false
18
29
  requirements:
19
30
  - - ! '>='
@@ -21,7 +32,7 @@ dependencies:
21
32
  version: '0'
22
33
  type: :development
23
34
  prerelease: false
24
- version_requirements: *70099189686620
35
+ version_requirements: *70311392067940
25
36
  description:
26
37
  email:
27
38
  - jean.boussier @nospam@ gmail.com
@@ -32,6 +43,7 @@ extra_rdoc_files: []
32
43
  files:
33
44
  - .gitignore
34
45
  - .rspec
46
+ - .travis.yml
35
47
  - Gemfile
36
48
  - README.md
37
49
  - Rakefile