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 +9 -0
- data/README.md +2 -0
- data/bin/getsub +88 -38
- data/lib/osdb/sub.rb +24 -8
- data/lib/osdb/version.rb +1 -1
- data/osdb.gemspec +1 -0
- metadata +16 -4
data/.travis.yml
ADDED
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
|
+
[](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
|
21
|
-
|
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
|
73
|
-
|
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
|
95
|
-
return
|
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
|
-
|
102
|
-
|
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
|
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
|
-
|
137
|
-
|
138
|
-
|
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
|
-
|
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, :
|
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
data/osdb.gemspec
CHANGED
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.
|
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
|
+
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: &
|
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: *
|
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
|