├── .gitignore ├── .rspec ├── .travis.yml ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── bin └── getsub ├── lib ├── osdb.rb └── osdb │ ├── finder.rb │ ├── finder │ ├── first.rb │ ├── interactive.rb │ └── score.rb │ ├── language.rb │ ├── movie.rb │ ├── movie_file.rb │ ├── search.rb │ ├── search │ ├── imdb.rb │ ├── movie_hash.rb │ ├── name.rb │ └── path.rb │ ├── selector.rb │ ├── selector │ ├── format.rb │ └── movie.rb │ ├── server.rb │ ├── sub.rb │ ├── subtitle_finder.rb │ ├── version.rb │ └── xmlrpc_monkey_patch.rb ├── osdb.gemspec └── spec ├── fixtures ├── http │ ├── check_movie_hash.yml │ ├── get_imdb_movie_details.yml │ ├── log_in.yml │ ├── log_out.yml │ ├── search_imdb.yml │ ├── search_subtitles_for_himym.yml │ ├── search_subtitles_for_the_rock.yml │ └── server_info.yml └── somemovie.avi ├── osdb ├── language_spec.rb ├── movie_file_spec.rb ├── server_spec.rb └── sub_spec.rb └── spec_helper.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | .bundle 3 | Gemfile.lock 4 | pkg/* 5 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | rvm: 3 | - 2.0 4 | - 2.1 5 | - 2.2 6 | - rbx 7 | - jruby 8 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | gemspec 4 | 5 | 6 | gem 'rake' 7 | gem 'rspec', '< 2.99' 8 | gem 'webmock', '~> 1.8.11' 9 | gem 'vcr', '~> 2.3.0' 10 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Jean Boussier 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OSDb 2 | 3 | Client library for the [OSDb protocol](http://trac.opensubtitles.org/projects/opensubtitles/wiki/XMLRPC). 4 | Currently the implentation is limited to movie identification and subtitles search 5 | 6 | [![Build Status](https://secure.travis-ci.org/byroot/ruby-osdb.png)](http://travis-ci.org/byroot/ruby-osdb) 7 | [![Gem Version](https://badge.fury.io/rb/osdb.png)](http://badge.fury.io/rb/osdb) 8 | 9 | ## Examples 10 | 11 | Just read the source of `bin/getsub` it is a typical example of OSDb's capacities. 12 | 13 | ## getsub 14 | 15 | The osdb gem provide a simple script to find and download the best subtitle on 16 | [opensubtitles.org](http://www.opensubtitles.org/) for your video file. 17 | 18 | ### Installation 19 | 20 | $ gem install osdb 21 | 22 | ### Usage 23 | 24 | You just have to execute `getsub` with some video files in arguments: 25 | 26 | $ getsub somemovie.avi othermovie.mkv 27 | 28 | Or specify a directory to search recursively: 29 | 30 | $ getsub ~/Movies 31 | 32 | For options details just run: 33 | 34 | $ getsub --help 35 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'rake' 3 | require 'rspec/core/rake_task' 4 | require 'bundler' 5 | 6 | Bundler::GemHelper.install_tasks 7 | RSpec::Core::RakeTask.new(:spec) 8 | 9 | task :default => :spec 10 | -------------------------------------------------------------------------------- /bin/getsub: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'optparse' 3 | require 'uri' 4 | require 'rubygems' 5 | require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'osdb')) 6 | 7 | 8 | class GetSub 9 | 10 | def initialize 11 | @options = {:language => OSDb.default_language.to_iso639_2b, :force => false, :dir => nil, :methods => 'h', :language_extension => false } 12 | @parser ||= OptionParser.new do |opts| 13 | opts.banner = "Automatically download subs for your video files using opensubtitle.org" 14 | opts.separator "" 15 | opts.separator "Usage: getsub [options] DIRECTORY | VIDEO_FILE [VIDEO_FILE ...]" 16 | opts.separator "" 17 | opts.separator "Main options:" 18 | 19 | opts.on("-a", "--auto", "Do not ask user to resolve hash conflicts.") { @options[:auto] = true } 20 | 21 | opts.on("-l", "--language LANGUAGE", "Sub language ISO 639-2 code like fre or eng. Default: env $LANG (#{OSDb.default_language.to_iso639_2b})") do |language| 22 | if language.to_s.length != 3 23 | STDERR.puts "Invalid argument: Language should specified as ISO 639-2 (ie, 3 letters, like 'eng' or 'fre')" 24 | exit 1 25 | end 26 | @options[:language] = language.to_s 27 | end 28 | 29 | opts.on("-f", "--force", "Download sub even if video already has one") { @options[:force] = true } 30 | 31 | opts.on("-t", "--type FORMATS", "Select only subtitles in specified formats. e.g -t srt,sub") { |formats| @options[:formats] = formats.to_s.split(',') } 32 | 33 | opts.on("-L", "--language-extension", "Add the ISO 639-2 in the subtitle's file extension. e.g filename.eng.srt" ) { @options[:language_extension] = true } 34 | 35 | methods_help = "Ordered list of search methods. h: by movie hash, i: by name on IMDB, n: by name on OSDb, p: by filename on OSDb. e.g -s hi . Default: h" 36 | opts.on("-s", "--search-by METHODS", methods_help) do |methods| 37 | unless methods =~ /^[hinp]+$/ 38 | STDERR.puts "Invalid argument: Available search methods are: h, i, n and p." 39 | exit 1 40 | end 41 | @options[:methods] = methods 42 | end 43 | 44 | end 45 | end 46 | 47 | def run!(files) 48 | @parser.parse! 49 | language = @options[:language] if @options[:language_extension] 50 | 51 | movie_files = glob(files).map{ |path| OSDb::MovieFile.new(path, language) } 52 | 53 | movie_files.each do |movie_file| 54 | begin 55 | puts "* Search subtitles for #{movie_file.name}" 56 | if movie_file.has_sub? && !@options[:force] 57 | puts "* Sub already there. To override it use --force" 58 | puts 59 | next 60 | end 61 | 62 | if sub = subtitle_finder.find_sub_for(movie_file, @options[:language]) 63 | download_sub!(sub, movie_file) 64 | else 65 | puts "* No sub found" 66 | end 67 | puts 68 | rescue Exception => e 69 | report_exception(e) 70 | end 71 | end 72 | end 73 | 74 | def glob(files) 75 | files.map do |path| 76 | if File.directory?(path) 77 | Dir.chdir(path) do # chdir to avoid escaping special chars in path 78 | relative_paths = Dir.glob("**/*.{#{OSDb::MovieFile::EXTENSIONS.join(',')}}") 79 | return relative_paths.map{ |f| File.join(path, f) } 80 | end 81 | else 82 | path 83 | end 84 | end.flatten 85 | end 86 | 87 | def report_exception(exception) 88 | puts 89 | puts "Something crashed." 90 | puts "Feel free to report the error here: https://github.com/byroot/ruby-osdb/issues" 91 | puts "With the following debug informations:" 92 | puts 93 | puts "#{exception.class.name}: #{exception.message}:" 94 | puts exception.backtrace 95 | puts 96 | end 97 | 98 | def subtitle_finder 99 | @subtitle_finder ||= OSDb::SubtitleFinder.new(search_engines, finders, selectors) 100 | end 101 | 102 | SEARCH_ENGINES = { 103 | 'h' => OSDb::Search::MovieHash, 104 | 'i' => OSDb::Search::IMDB, 105 | 'n' => OSDb::Search::Name, 106 | 'p' => OSDb::Search::Path 107 | } 108 | 109 | def search_engines 110 | @options[:methods].to_s.each_char.to_a.uniq.map do |char| 111 | SEARCH_ENGINES[char.to_s].new(server) 112 | end 113 | end 114 | 115 | def finders 116 | [OSDb::Finder::Score.new] 117 | end 118 | 119 | def selectors 120 | movie_finder = if @options[:auto] 121 | OSDb::Finder::First.new # TODO: try to match subtitle movie name with filename 122 | else 123 | OSDb::Finder::Interactive.new 124 | end 125 | 126 | selectors = [ 127 | OSDb::Selector::Movie.new(movie_finder) 128 | ] 129 | selectors << OSDb::Selector::Format.new(@options[:formats]) if @options[:formats] 130 | selectors 131 | end 132 | 133 | def server 134 | @server ||= OSDb::Server.new( 135 | :timeout => 90, 136 | :useragent => "SubDownloader 2.0.10" # register useragent ? WTF ? too boring. 137 | ) 138 | end 139 | 140 | def download_sub!(sub, movie_file) 141 | local_path = movie_file.sub_path(sub.format) 142 | print "* download #{sub.url} to #{local_path} ... " 143 | content = sub.body 144 | unless content 145 | puts "failed" 146 | return 147 | end 148 | 149 | File.open(movie_file.sub_path(sub.format), 'w+') do |file| 150 | file.write(content) 151 | end 152 | puts "done" 153 | end 154 | 155 | end 156 | 157 | GetSub.new.run!(ARGV) 158 | -------------------------------------------------------------------------------- /lib/osdb.rb: -------------------------------------------------------------------------------- 1 | require 'xmlrpc/client' 2 | 3 | module OSDb 4 | base_path = File.expand_path(File.dirname(__FILE__) + '/osdb') 5 | require "#{base_path}/xmlrpc_monkey_patch" 6 | 7 | autoload :Finder, "#{base_path}/finder" 8 | autoload :Language, "#{base_path}/language" 9 | autoload :Movie, "#{base_path}/movie" 10 | autoload :MovieFile, "#{base_path}/movie_file" 11 | autoload :Search, "#{base_path}/search" 12 | autoload :Selector, "#{base_path}/selector" 13 | autoload :Server, "#{base_path}/server" 14 | autoload :Sub, "#{base_path}/sub" 15 | autoload :SubtitleFinder, "#{base_path}/subtitle_finder" 16 | 17 | def self.default_language 18 | OSDb::Language.from_locale(ENV['LANG'] || 'en_US.UTF-8') 19 | end 20 | 21 | end 22 | -------------------------------------------------------------------------------- /lib/osdb/finder.rb: -------------------------------------------------------------------------------- 1 | module OSDb 2 | module Finder 3 | base_path = File.expand_path(File.dirname(__FILE__) + '/finder') 4 | autoload :First, "#{base_path}/first" 5 | autoload :Interactive, "#{base_path}/interactive" 6 | autoload :Score, "#{base_path}/score" 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/osdb/finder/first.rb: -------------------------------------------------------------------------------- 1 | module OSDb 2 | module Finder 3 | 4 | class First 5 | 6 | def chose(items) 7 | items.first 8 | end 9 | 10 | end 11 | 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/osdb/finder/interactive.rb: -------------------------------------------------------------------------------- 1 | module OSDb 2 | module Finder 3 | 4 | class Interactive 5 | 6 | def chose(items) 7 | puts "D'oh! You stumbled upon a hash conflict, please resolve it:" 8 | puts 9 | items.each_with_index do |name, index| 10 | puts " #{index} - #{name}" 11 | end 12 | print 'id: ' 13 | str = STDIN.gets # TODO: rule #1, never trust user input 14 | puts 15 | items[str.to_i] 16 | end 17 | 18 | end 19 | 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/osdb/finder/score.rb: -------------------------------------------------------------------------------- 1 | module OSDb 2 | module Finder 3 | 4 | class Score 5 | 6 | def chose(items) 7 | items.max_by(&:score) 8 | end 9 | 10 | end 11 | 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/osdb/language.rb: -------------------------------------------------------------------------------- 1 | module OSDb 2 | 3 | LANGUAGES = [ 4 | {:iso639_1 => 'sq', :iso639_2b => 'alb', :locale => 'sq', :name => 'Albanian'}, 5 | {:iso639_1 => 'ar', :iso639_2b => 'ara', :locale => 'ar', :name => 'Arabic'}, 6 | {:iso639_1 => 'hy', :iso639_2b => 'arm', :locale => 'hy', :name => 'Armenian'}, 7 | {:iso639_1 => 'ms', :iso639_2b => 'may', :locale => 'ms', :name => 'Malay'}, 8 | {:iso639_1 => 'bs', :iso639_2b => 'bos', :locale => 'bs', :name => 'Bosnian'}, 9 | {:iso639_1 => 'bg', :iso639_2b => 'bul', :locale => 'bg', :name => 'Bulgarian'}, 10 | {:iso639_1 => 'ca', :iso639_2b => 'cat', :locale => 'ca', :name => 'Catalan'}, 11 | {:iso639_1 => 'eu', :iso639_2b => 'eus', :locale => 'eu', :name => 'Basque'}, 12 | {:iso639_1 => 'zh', :iso639_2b => 'chi', :locale => 'zh_CN', :name => 'Chinese (China)'}, 13 | {:iso639_1 => 'hr', :iso639_2b => 'hrv', :locale => 'hr', :name => 'Croatian'}, 14 | {:iso639_1 => 'cs', :iso639_2b => 'cze', :locale => 'cs', :name => 'Czech'}, 15 | {:iso639_1 => 'da', :iso639_2b => 'dan', :locale => 'da', :name => 'Danish'}, 16 | {:iso639_1 => 'nl', :iso639_2b => 'dut', :locale => 'nl', :name => 'Dutch'}, 17 | {:iso639_1 => 'en', :iso639_2b => 'eng', :locale => 'en', :name => 'English (US)'}, 18 | {:iso639_1 => 'en', :iso639_2b => 'bre', :locale => 'en_GB', :name => 'English (UK)'}, 19 | {:iso639_1 => 'eo', :iso639_2b => 'epo', :locale => 'eo', :name => 'Esperanto'}, 20 | {:iso639_1 => 'et', :iso639_2b => 'est', :locale => 'et', :name => 'Estonian'}, 21 | {:iso639_1 => 'fi', :iso639_2b => 'fin', :locale => 'fi', :name => 'Finnish'}, 22 | {:iso639_1 => 'fr', :iso639_2b => 'fre', :locale => 'fr', :name => 'French'}, 23 | {:iso639_1 => 'gl', :iso639_2b => 'glg', :locale => 'gl', :name => 'Galician'}, 24 | {:iso639_1 => 'ka', :iso639_2b => 'geo', :locale => 'ka', :name => 'Georgian'}, 25 | {:iso639_1 => 'de', :iso639_2b => 'ger', :locale => 'de', :name => 'German'}, 26 | {:iso639_1 => 'el', :iso639_2b => 'ell', :locale => 'el', :name => 'Greek'}, 27 | {:iso639_1 => 'he', :iso639_2b => 'heb', :locale => 'he', :name => 'Hebrew'}, 28 | {:iso639_1 => 'hu', :iso639_2b => 'hun', :locale => 'hu', :name => 'Hungarian'}, 29 | {:iso639_1 => 'id', :iso639_2b => 'ind', :locale => 'id', :name => 'Indonesian'}, 30 | {:iso639_1 => 'it', :iso639_2b => 'ita', :locale => 'it', :name => 'Italian'}, 31 | {:iso639_1 => 'ja', :iso639_2b => 'jpn', :locale => 'ja', :name => 'Japanese'}, 32 | {:iso639_1 => 'kk', :iso639_2b => 'kaz', :locale => 'kk', :name => 'Kazakh'}, 33 | {:iso639_1 => 'ko', :iso639_2b => 'kor', :locale => 'ko', :name => 'Korean'}, 34 | {:iso639_1 => 'lv', :iso639_2b => 'lav', :locale => 'lv', :name => 'Latvian'}, 35 | {:iso639_1 => 'lt', :iso639_2b => 'lit', :locale => 'lt', :name => 'Lithuanian'}, 36 | {:iso639_1 => 'lb', :iso639_2b => 'ltz', :locale => 'lb', :name => 'Luxembourgish'}, 37 | {:iso639_1 => 'mk', :iso639_2b => 'mac', :locale => 'mk', :name => 'Macedonian'}, 38 | {:iso639_1 => 'no', :iso639_2b => 'nor', :locale => 'no', :name => 'Norwegian'}, 39 | {:iso639_1 => 'fa', :iso639_2b => 'per', :locale => 'fa', :name => 'Persian'}, 40 | {:iso639_1 => 'pl', :iso639_2b => 'pol', :locale => 'pl', :name => 'Polish'}, 41 | {:iso639_1 => 'pt', :iso639_2b => 'por', :locale => 'pt_PT', :name => 'Portuguese (Portugal)'}, 42 | {:iso639_1 => 'pb', :iso639_2b => 'pob', :locale => 'pt_BR', :name => 'Portuguese (Brazil)'}, 43 | {:iso639_1 => 'ro', :iso639_2b => 'rum', :locale => 'ro', :name => 'Romanian'}, 44 | {:iso639_1 => 'ru', :iso639_2b => 'rus', :locale => 'ru', :name => 'Russian'}, 45 | {:iso639_1 => 'sr', :iso639_2b => 'scc', :locale => 'sr', :name => 'Serbian'}, 46 | {:iso639_1 => 'sk', :iso639_2b => 'slo', :locale => 'sk', :name => 'Slovak'}, 47 | {:iso639_1 => 'sl', :iso639_2b => 'slv', :locale => 'sl', :name => 'Slovenian'}, 48 | {:iso639_1 => 'es', :iso639_2b => 'spa', :locale => 'es_ES', :name => 'Spanish (Spain)'}, 49 | {:iso639_1 => 'sv', :iso639_2b => 'swe', :locale => 'sv', :name => 'Swedish'}, 50 | {:iso639_1 => 'th', :iso639_2b => 'tha', :locale => 'th', :name => 'Thai'}, 51 | {:iso639_1 => 'tr', :iso639_2b => 'tur', :locale => 'tr', :name => 'Turkish'}, 52 | {:iso639_1 => 'uk', :iso639_2b => 'ukr', :locale => 'uk', :name => 'Ukrainian'}, 53 | {:iso639_1 => 'vi', :iso639_2b => 'vie', :locale => 'vi', :name => 'Vietnamese'} 54 | ] 55 | 56 | class Language 57 | 58 | class << self 59 | 60 | def from_locale(locale) 61 | locale = locale.split('.').first 62 | lang = LANGUAGES.find{ |lang| lang[:locale] == locale } 63 | return from_locale(locale.split('_').first) if !lang && locale.include?('_') 64 | new(lang) 65 | end 66 | 67 | def from_iso639_2b(code) 68 | new(LANGUAGES.find{ |lang| lang[:iso639_2b] == code }) 69 | end 70 | 71 | end 72 | 73 | attr_reader :name, :to_iso639_1, :to_iso639_2b, :to_locale 74 | 75 | def initialize(hash) 76 | @name = hash[:name] 77 | @to_iso639_1 = hash[:iso639_1] 78 | @to_iso639_2b = hash[:iso639_2b] 79 | @to_locale = hash[:locale] 80 | end 81 | 82 | end 83 | 84 | end 85 | -------------------------------------------------------------------------------- /lib/osdb/movie.rb: -------------------------------------------------------------------------------- 1 | module OSDb 2 | class Movie 3 | 4 | attr_reader :id, :title, :year, :cover, :rating, :raw_data 5 | 6 | def initialize(data) 7 | @id = data['id'] 8 | @title = data['title'] 9 | @year = data['year'] && data['year'].to_i 10 | @cover = data['cover'] 11 | @rating = data['rating'] && data['rating'].to_f 12 | @raw_data = data 13 | end 14 | 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/osdb/movie_file.rb: -------------------------------------------------------------------------------- 1 | module OSDb 2 | class MovieFile 3 | 4 | EXTENSIONS = %w(avi mpg m4v mkv mov ogv mp4) 5 | 6 | attr_reader :path, :language 7 | 8 | def initialize(path, language = OSDb.default_language) 9 | @path = path 10 | @language = language 11 | end 12 | 13 | def has_sub? 14 | exist = false 15 | %w(srt sub).each{ |ext| exist ||= File.exist?(sub_path(ext)) } 16 | exist 17 | end 18 | 19 | def sub_path(format) 20 | extension = if @language 21 | ".#{@language}.#{format}" 22 | else 23 | ".#{format}" 24 | end 25 | File.join(File.dirname(path), File.basename(path, File.extname(path)) + extension) 26 | end 27 | 28 | def hash 29 | @hash ||= self.class.compute_hash(path) 30 | end 31 | 32 | def size 33 | @size ||= File.size(path) 34 | end 35 | 36 | def name 37 | @name ||= File.basename(path, File.extname(path)) 38 | end 39 | 40 | CHUNK_SIZE = 64 * 1024 # in bytes 41 | 42 | # from http://trac.opensubtitles.org/projects/opensubtitles/wiki/HashSourceCodes 43 | def self.compute_hash(path) 44 | filesize = File.size(path) 45 | hash = filesize 46 | 47 | # Read 64 kbytes, divide up into 64 bits and add each 48 | # to hash. Do for beginning and end of file. 49 | File.open(path, 'rb') do |f| 50 | # Q = unsigned long long = 64 bit 51 | f.read(CHUNK_SIZE).unpack("Q*").each do |n| 52 | hash = hash + n & 0xffffffffffffffff # to remain as 64 bit number 53 | end 54 | 55 | f.seek([0, filesize - CHUNK_SIZE].max, IO::SEEK_SET) 56 | 57 | # And again for the end of the file 58 | f.read(CHUNK_SIZE).unpack("Q*").each do |n| 59 | hash = hash + n & 0xffffffffffffffff 60 | end 61 | end 62 | 63 | sprintf("%016x", hash) 64 | end 65 | 66 | end 67 | end 68 | -------------------------------------------------------------------------------- /lib/osdb/search.rb: -------------------------------------------------------------------------------- 1 | module OSDb 2 | module Search 3 | base_path = File.expand_path(File.dirname(__FILE__) + '/search') 4 | autoload :IMDB, "#{base_path}/imdb" 5 | autoload :MovieHash, "#{base_path}/movie_hash" 6 | autoload :Name, "#{base_path}/name" 7 | autoload :Path, "#{base_path}/path" 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/osdb/search/imdb.rb: -------------------------------------------------------------------------------- 1 | module OSDb 2 | module Search 3 | 4 | class IMDB 5 | 6 | def initialize(server, selector=Finder::First.new) 7 | @server = server 8 | @selector = selector 9 | end 10 | 11 | def search_subs_for(movie, language) 12 | imdb_results = @server.search_imdb(:query => movie.name) 13 | return if imdb_results.size == 0 14 | return if imdb_results.class != Hash 15 | return if imdb_results[:imdbid] == nil 16 | if imdb_result = @selector.chose(imdb_results) 17 | @server.search_subtitles( 18 | :sublanguageid => language, 19 | :imdbid => imdb_result.imdbid 20 | ) 21 | end 22 | end 23 | 24 | end 25 | 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /lib/osdb/search/movie_hash.rb: -------------------------------------------------------------------------------- 1 | module OSDb 2 | module Search 3 | 4 | class MovieHash 5 | 6 | def initialize(server) 7 | @server = server 8 | end 9 | 10 | def search_subs_for(movie, language) 11 | @server.search_subtitles( 12 | :moviehash => movie.hash, 13 | :moviebytesize => movie.size.to_s, 14 | :sublanguageid => language 15 | ) 16 | end 17 | 18 | end 19 | 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/osdb/search/name.rb: -------------------------------------------------------------------------------- 1 | module OSDb 2 | module Search 3 | 4 | class Name 5 | 6 | def initialize(server) 7 | @server = server 8 | end 9 | 10 | def search_subs_for(movie, language) 11 | subs = @server.search_subtitles(:sublanguageid => language, :query => movie.name) 12 | normalized_movie_name = normalize_name(movie.name) 13 | subs.select! do |sub| 14 | normalize_name(sub.filename).index(normalized_movie_name) # MAYBE: Levenshtein ? 15 | end 16 | subs 17 | end 18 | 19 | protected 20 | 21 | def normalize_name(name) 22 | name.downcase.gsub(/[\s\.\-\_]+/, ' ') 23 | end 24 | 25 | end 26 | 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /lib/osdb/search/path.rb: -------------------------------------------------------------------------------- 1 | module OSDb 2 | module Search 3 | 4 | class Path 5 | 6 | def initialize(server) 7 | @server = server 8 | end 9 | 10 | def search_subs_for(movie, language) 11 | @server.search_subtitles( 12 | :sublanguageid => language, 13 | :tag => movie.path 14 | ) 15 | end 16 | 17 | end 18 | 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /lib/osdb/selector.rb: -------------------------------------------------------------------------------- 1 | module OSDb 2 | module Selector 3 | base_path = File.expand_path(File.dirname(__FILE__) + '/selector') 4 | autoload :Format, "#{base_path}/format" 5 | autoload :Movie, "#{base_path}/movie" 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /lib/osdb/selector/format.rb: -------------------------------------------------------------------------------- 1 | module OSDb 2 | module Selector 3 | 4 | class Format 5 | 6 | def initialize(formats) 7 | @formats = formats 8 | end 9 | 10 | def select(subs, movie) 11 | subs.select{ |s| @formats.include?(s.format) } 12 | end 13 | 14 | end 15 | 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/osdb/selector/movie.rb: -------------------------------------------------------------------------------- 1 | module OSDb 2 | module Selector 3 | 4 | class Movie 5 | 6 | def initialize(movie_finder=Finder::First.new) 7 | @movie_finder = movie_finder 8 | end 9 | 10 | def select(subs, movie) 11 | subs_by_movie = group_by_movie_name(subs) 12 | return subs if subs_by_movie.length <= 1 13 | movie_names = subs_by_movie.keys 14 | movie_name = @movie_finder.chose(movie_names) 15 | subs_by_movie[movie_name] || [] 16 | end 17 | 18 | def group_by_movie_name(subs) 19 | subs.inject({}) do |hash, sub| 20 | hash[sub.movie_name] ||= [] 21 | hash[sub.movie_name] << sub 22 | hash 23 | end 24 | end 25 | 26 | end 27 | 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /lib/osdb/server.rb: -------------------------------------------------------------------------------- 1 | require 'ostruct' 2 | 3 | module OSDb 4 | 5 | class LoginFailed < ::Exception 6 | end 7 | 8 | class Server 9 | 10 | attr_reader :username, :password, :language, :useragent, :client 11 | 12 | CLIENT_ARGS = [:host, :path, :port, :proxy_host, :proxy_port, :http_user, :http_password, :use_ssl, :timeout] 13 | 14 | DEFAULT_OPTIONS = { 15 | :host => 'api.opensubtitles.org', 16 | :path => '/xml-rpc', 17 | :timeout => 10 18 | }.freeze 19 | 20 | def initialize(options={}) 21 | @username = options[:username] || '' 22 | @password = options[:password] || '' 23 | @language = options[:language] || 'eng' 24 | @useragent = options[:useragent] || 'ruby-osdb v0.1' 25 | options = DEFAULT_OPTIONS.merge(options) 26 | @client = ::XMLRPC::Client.new(*options.values_at(*CLIENT_ARGS)) 27 | end 28 | 29 | def token 30 | @token ||= login 31 | end 32 | 33 | def login 34 | response = client.call('LogIn', username, password, language, useragent) 35 | if response['status'] != '200 OK' 36 | raise LoginFailed.new("Failed to login with #{username} : #{password}. Server return code: #{response['status']}") 37 | end 38 | response['token'] 39 | end 40 | 41 | def logout 42 | client.call('LogOut', token) 43 | @token = nil 44 | end 45 | 46 | def check_movie_hash(*hashes) 47 | client.call('CheckMovieHash', token, hashes) 48 | end 49 | 50 | def search_subtitles(*queries) 51 | subs = client.call('SearchSubtitles', token, queries)['data'] 52 | subs ? subs.map{ |s| Sub.new(s) } : [] 53 | end 54 | 55 | def search_imdb(options={}) 56 | query = options.delete(:query) 57 | imdb = client.call('SearchMoviesOnIMDB', token, query)['data'] 58 | imdb.size > 0 ? imdb.map{ |i| OpenStruct.new(:imdbid => i['id'], :title => i['title']) } : [] 59 | end 60 | 61 | def info 62 | client.call('ServerInfo') 63 | end 64 | 65 | def get_imdb_movie_details(id) 66 | Movie.new(client.call('GetIMDBMovieDetails', token, id)['data']) 67 | end 68 | 69 | end 70 | end 71 | -------------------------------------------------------------------------------- /lib/osdb/sub.rb: -------------------------------------------------------------------------------- 1 | require 'uri' 2 | require 'net/http' 3 | require 'zlib' 4 | require 'stringio' 5 | 6 | module OSDb 7 | 8 | class Sub 9 | 10 | attr_reader :url, :format, :language, :rating, :user_ranks, :movie_name, 11 | :filename, :raw_data, :downloads_count, :bad_reports_count 12 | 13 | def initialize(data) 14 | @url = URI.parse(data['SubDownloadLink']) 15 | @format = data['SubFormat'] 16 | @language = Language.from_iso639_2b(data['SubLanguageID']) 17 | @rating = data['SubRating'].to_f 18 | @user_ranks = data['UserRank'] 19 | @movie_name = data['MovieName'] 20 | @filename = data['SubFileName'] 21 | @downloads_count = data['SubDownloadsCnt'].to_i 22 | @bad_reports_count = data['SubBad'].to_i 23 | @raw_data = data 24 | end 25 | 26 | def <=>(other) 27 | rating <=> other.rating 28 | end 29 | 30 | # Totaly subjective formula to evaluate subtitle quality 31 | # Originaly developed by runa (https://github.com/runa) 32 | # https://github.com/byroot/ruby-osdb/commit/9d71775#L0R122 33 | def score 34 | uploader_score * downloads_count.next * (rating + 1) - bad_reports_count / downloads_count.next 35 | end 36 | 37 | def uploader_score 38 | user_ranks.empty? ? 1 : 2 39 | end 40 | 41 | def body 42 | @body ||= fetch_body 43 | end 44 | 45 | def fetch_body 46 | StringIO.open do |buffer| 47 | buffer.write(Net::HTTP.get(url)) 48 | buffer.rewind 49 | return Zlib::GzipReader.new(buffer).read 50 | end 51 | end 52 | 53 | end 54 | 55 | end 56 | -------------------------------------------------------------------------------- /lib/osdb/subtitle_finder.rb: -------------------------------------------------------------------------------- 1 | module OSDb 2 | 3 | class SubtitleFinder 4 | 5 | def initialize(search_engines, finders, selectors=[]) 6 | @search_engines = search_engines 7 | @finders = finders 8 | @selectors = selectors 9 | end 10 | 11 | def find_sub_for(movie, language) 12 | @search_engines.each do |engine| 13 | subs = engine.search_subs_for(movie, language) 14 | unless subs.nil? 15 | subs = @selectors.inject(subs) do |subs, selector| 16 | selector.select(subs, movie) 17 | end 18 | @finders.each do |finder| 19 | sub = finder.chose(subs) 20 | return sub if sub 21 | end 22 | end 23 | end 24 | 25 | nil 26 | end 27 | 28 | end 29 | 30 | end 31 | -------------------------------------------------------------------------------- /lib/osdb/version.rb: -------------------------------------------------------------------------------- 1 | module OSDb 2 | VERSION = '0.2.2' 3 | end 4 | -------------------------------------------------------------------------------- /lib/osdb/xmlrpc_monkey_patch.rb: -------------------------------------------------------------------------------- 1 | # OpenSubtitle.org return invalid content-length that mek the stdlib xmlrpc client raise 2 | # This is a dirty monkey patch to workaround this. :'( 3 | 4 | module XMLRPC 5 | class Client 6 | def do_rpc(request, async=false) 7 | header = { 8 | "User-Agent" => USER_AGENT, 9 | "Content-Type" => "text/xml; charset=utf-8", 10 | "Content-Length" => request.bytesize.to_s, 11 | "Connection" => (async ? "close" : "keep-alive") 12 | } 13 | 14 | header["Cookie"] = @cookie if @cookie 15 | header.update(@http_header_extra) if @http_header_extra 16 | 17 | if @auth != nil 18 | # add authorization header 19 | header["Authorization"] = @auth 20 | end 21 | 22 | resp = nil 23 | @http_last_response = nil 24 | 25 | if async 26 | # use a new HTTP object for each call 27 | http = net_http(@host, @port, @proxy_host, @proxy_port) 28 | http.use_ssl = @use_ssl if @use_ssl 29 | http.read_timeout = @timeout 30 | http.open_timeout = @timeout 31 | 32 | # post request 33 | http.start { 34 | resp = http.request_post(@path, request, header) 35 | } 36 | else 37 | # reuse the HTTP object for each call => connection alive is possible 38 | # we must start connection explicitely first time so that http.request 39 | # does not assume that we don't want keepalive 40 | @http.start if not @http.started? 41 | 42 | # post request 43 | resp = @http.request_post(@path, request, header) 44 | end 45 | 46 | @http_last_response = resp 47 | 48 | data = resp.body 49 | 50 | if resp.code == "401" 51 | # Authorization Required 52 | raise "Authorization failed.\nHTTP-Error: #{resp.code} #{resp.message}" 53 | elsif resp.code[0,1] != "2" 54 | raise "HTTP-Error: #{resp.code} #{resp.message}" 55 | end 56 | 57 | # assume text/xml on instances where Content-Type header is not set 58 | ct_expected = resp["Content-Type"] || 'text/xml' 59 | ct = parse_content_type(ct_expected).first 60 | if ct != "text/xml" 61 | if ct == "text/html" 62 | raise "Wrong content-type (received '#{ct}' but expected 'text/xml'): \n#{data}" 63 | else 64 | raise "Wrong content-type (received '#{ct}' but expected 'text/xml')" 65 | end 66 | end 67 | 68 | expected = resp["Content-Length"] || "" 69 | if data.nil? or data.bytesize == 0 70 | raise "Wrong size. Was #{data.bytesize}, should be #{expected}" 71 | elsif expected != "" and expected.to_i != data.bytesize and resp["Transfer-Encoding"].nil? 72 | # HACK: here is the monkey patched line 73 | # raise "Wrong size. Was #{data.bytesize}, should be #{expected}" 74 | end 75 | 76 | set_cookies = resp.get_fields("Set-Cookie") 77 | if set_cookies and !set_cookies.empty? 78 | require 'webrick/cookie' 79 | @cookie = set_cookies.collect do |set_cookie| 80 | cookie = WEBrick::Cookie.parse_set_cookie(set_cookie) 81 | WEBrick::Cookie.new(cookie.name, cookie.value).to_s 82 | end.join("; ") 83 | end 84 | 85 | return data 86 | end 87 | end 88 | end 89 | -------------------------------------------------------------------------------- /osdb.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | $:.push File.expand_path("../lib", __FILE__) 3 | require "osdb/version" 4 | 5 | Gem::Specification.new do |s| 6 | s.name = "osdb" 7 | s.version = OSDb::VERSION 8 | s.authors = ["Jean Boussier"] 9 | s.email = ["jean.boussier @nospam@ gmail.com"] 10 | s.homepage = %q{http://github.com/byroot/ruby-osdb} 11 | s.summary = %q{Ruby library to access OSDb services like OpenSubtitles.org} 12 | 13 | s.rubyforge_project = "osdb" 14 | 15 | s.files = `git ls-files`.split("\n") 16 | s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") 17 | s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } 18 | s.require_paths = ["lib"] 19 | s.license = 'MIT' 20 | end 21 | -------------------------------------------------------------------------------- /spec/fixtures/http/check_movie_hash.yml: -------------------------------------------------------------------------------- 1 | --- 2 | http_interactions: 3 | - request: 4 | method: post 5 | uri: http://api.opensubtitles.org/xml-rpc 6 | body: 7 | string: | 8 | LogInengOS Test User Agent 9 | 10 | headers: 11 | Accept: 12 | - "*/*" 13 | Cookie: 14 | - PHPSESSID=qtqkphpa0us78eikqtdtg4jic7 15 | Content-Length: 16 | - "304" 17 | User-Agent: 18 | - XMLRPC::Client (Ruby 1.8.7) 19 | Content-Type: 20 | - text/xml; charset=utf-8 21 | Connection: 22 | - keep-alive 23 | response: 24 | status: 25 | code: 200 26 | message: OK 27 | headers: 28 | X-Cache: 29 | - MISS 30 | Age: 31 | - "0" 32 | X-Cache-Backend: 33 | - www 34 | Cache-Control: 35 | - no-store, no-cache, must-revalidate, post-check=0, pre-check=0 36 | Pragma: 37 | - no-cache 38 | Expires: 39 | - Thu, 19 Nov 1981 08:52:00 GMT 40 | Content-Length: 41 | - "504" 42 | Content-Type: 43 | - text/xml 44 | Connection: 45 | - keep-alive 46 | Accept-Ranges: 47 | - bytes 48 | Date: 49 | - Sun, 04 Nov 2012 17:11:36 GMT 50 | body: 51 | string: | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | token 60 | 61 | qtqkphpa0us78eikqtdtg4jic7 62 | 63 | 64 | 65 | status 66 | 67 | 200 OK 68 | 69 | 70 | 71 | seconds 72 | 73 | 0.009 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | http_version: 83 | recorded_at: Sun, 04 Nov 2012 17:11:36 GMT 84 | - request: 85 | method: post 86 | uri: http://api.opensubtitles.org/xml-rpc 87 | body: 88 | string: | 89 | CheckMovieHashqtqkphpa0us78eikqtdtg4jic737d0c7d0cfcbe280 90 | 91 | headers: 92 | Accept: 93 | - "*/*" 94 | Cookie: 95 | - PHPSESSID=qtqkphpa0us78eikqtdtg4jic7 96 | Content-Length: 97 | - "283" 98 | User-Agent: 99 | - XMLRPC::Client (Ruby 1.8.7) 100 | Content-Type: 101 | - text/xml; charset=utf-8 102 | Connection: 103 | - keep-alive 104 | response: 105 | status: 106 | code: 200 107 | message: OK 108 | headers: 109 | X-Cache: 110 | - MISS 111 | Age: 112 | - "0" 113 | X-Cache-Backend: 114 | - www 115 | Cache-Control: 116 | - no-store, no-cache, must-revalidate, post-check=0, pre-check=0 117 | Set-Cookie: 118 | - PHPSESSID=qtqkphpa0us78eikqtdtg4jic7; path=/ 119 | Pragma: 120 | - no-cache 121 | Expires: 122 | - Thu, 19 Nov 1981 08:52:00 GMT 123 | Content-Length: 124 | - "1800" 125 | Content-Type: 126 | - text/xml 127 | Connection: 128 | - keep-alive 129 | Accept-Ranges: 130 | - bytes 131 | Date: 132 | - Sun, 04 Nov 2012 17:11:36 GMT 133 | body: 134 | string: | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | status 143 | 144 | 200 OK 145 | 146 | 147 | 148 | data 149 | 150 | 151 | 152 | 37d0c7d0cfcbe280 153 | 154 | 155 | 156 | MovieHash 157 | 158 | 37d0c7d0cfcbe280 159 | 160 | 161 | 162 | MovieImdbID 163 | 164 | 0117500 165 | 166 | 167 | 168 | MovieName 169 | 170 | The Rock 171 | 172 | 173 | 174 | MovieYear 175 | 176 | 1996 177 | 178 | 179 | 180 | MovieKind 181 | 182 | movie 183 | 184 | 185 | 186 | SeriesSeason 187 | 188 | 0 189 | 190 | 191 | 192 | SeriesEpisode 193 | 194 | 0 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | not_processed 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | seconds 213 | 214 | 0.016 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | http_version: 224 | recorded_at: Sun, 04 Nov 2012 17:11:36 GMT 225 | recorded_with: VCR 2.3.0 226 | -------------------------------------------------------------------------------- /spec/fixtures/http/get_imdb_movie_details.yml: -------------------------------------------------------------------------------- 1 | --- 2 | http_interactions: 3 | - request: 4 | method: post 5 | uri: http://api.opensubtitles.org/xml-rpc 6 | body: 7 | string: | 8 | GetIMDBMovieDetailsqtqkphpa0us78eikqtdtg4jic70176415 9 | 10 | headers: 11 | Accept: 12 | - "*/*" 13 | Cookie: 14 | - PHPSESSID=qtqkphpa0us78eikqtdtg4jic7 15 | Content-Length: 16 | - "236" 17 | User-Agent: 18 | - XMLRPC::Client (Ruby 1.8.7) 19 | Content-Type: 20 | - text/xml; charset=utf-8 21 | Connection: 22 | - keep-alive 23 | response: 24 | status: 25 | code: 200 26 | message: OK 27 | headers: 28 | X-Cache: 29 | - MISS 30 | Age: 31 | - "0" 32 | X-Cache-Backend: 33 | - www 34 | Cache-Control: 35 | - no-store, no-cache, must-revalidate, post-check=0, pre-check=0 36 | Set-Cookie: 37 | - PHPSESSID=qtqkphpa0us78eikqtdtg4jic7; path=/ 38 | Pragma: 39 | - no-cache 40 | Expires: 41 | - Thu, 19 Nov 1981 08:52:00 GMT 42 | Content-Length: 43 | - "6866" 44 | Content-Type: 45 | - text/xml 46 | Connection: 47 | - keep-alive 48 | Accept-Ranges: 49 | - bytes 50 | Date: 51 | - Sun, 04 Nov 2012 17:11:59 GMT 52 | body: 53 | string: | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | status 62 | 63 | 200 OK 64 | 65 | 66 | 67 | data 68 | 69 | 70 | 71 | cast 72 | 73 | 74 | 75 | _0273178 76 | 77 | Fernando Fernán Gómez 78 | 79 | 80 | 81 | _0022264 82 | 83 | Rafael Alonso 84 | 85 | 86 | 87 | _0347201 88 | 89 | Cayetana Guillén Cuervo 90 | 91 | 92 | 93 | _0328020 94 | 95 | Agustín González 96 | 97 | 98 | 99 | _0190285 100 | 101 | Cristina Cruz 102 | 103 | 104 | 105 | _0747510 106 | 107 | Alicia Rozas 108 | 109 | 110 | 111 | _0347218 112 | 113 | Fernando Guillén 114 | 115 | 116 | 117 | _0685037 118 | 119 | Francisco Piquer 120 | 121 | 122 | 123 | _0557456 124 | 125 | María Massip 126 | 127 | 128 | 129 | _0137138 130 | 131 | José Caride 132 | 133 | 134 | 135 | _0019330 136 | 137 | Francisco Algora 138 | 139 | 140 | 141 | _0169358 142 | 143 | Emma Cohen 144 | 145 | 146 | 147 | _0130703 148 | 149 | Juan Calot 150 | 151 | 152 | 153 | _0350881 154 | 155 | Concha Gómez Conde 156 | 157 | 158 | 159 | _0736047 160 | 161 | Nuria Rodríguez 162 | 163 | 164 | 165 | 166 | 167 | 168 | writers 169 | 170 | 171 | 172 | _0305054 173 | 174 | José Luis Garci 175 | 176 | 177 | 178 | _0701918 179 | 180 | Benito Pérez Galdós 181 | 182 | 183 | 184 | 185 | 186 | 187 | rating 188 | 189 | 7.4 190 | 191 | 192 | 193 | kind 194 | 195 | movie 196 | 197 | 198 | 199 | cover 200 | 201 | http://ia.media-imdb.com/images/M/MV5BMTkwNzIxMTgzMF5BMl5BanBnXkFtZTYwOTkyMTA5._V1._SY317_CR5,0,214,317_.jpg 202 | 203 | 204 | 205 | awards 206 | 207 | 208 | 209 | 210 | Nominated for Oscar. Another 9 wins & 17 nominations 211 | 212 | 213 | 214 | 215 | 216 | 217 | genres 218 | 219 | 220 | 221 | 222 | Drama 223 | 224 | 225 | 226 | 227 | 228 | 229 | id 230 | 231 | 0176415 232 | 233 | 234 | 235 | votes 236 | 237 | 1056 238 | 239 | 240 | 241 | country 242 | 243 | 244 | 245 | 246 | Spain 247 | 248 | 249 | 250 | 251 | 252 | 253 | language 254 | 255 | 256 | 257 | 258 | Spanish 259 | 260 | 261 | 262 | 263 | 264 | 265 | directors 266 | 267 | 268 | 269 | _0305054 270 | 271 | José Luis Garci 272 | 273 | 274 | 275 | 276 | 277 | 278 | duration 279 | 280 | 151 min 281 | 282 | 283 | 284 | plot 285 | 286 | After his son dies, an elderly man comes back to Spain from the US and hopes to find out which of his granddaughters is true, and which one is bastard. 287 | 288 | 289 | 290 | title 291 | 292 | El abuelo 293 | 294 | 295 | 296 | aka 297 | 298 | 299 | 300 | 301 | The Grandfather (Canada (English title) / International (English title) / USA) 302 | 303 | 304 | A nagyapa (Hungary (imdb display title)) 305 | 306 | 307 | Dziadek (Poland) 308 | 309 | 310 | 311 | 312 | 313 | 314 | year 315 | 316 | 1998 317 | 318 | 319 | 320 | request_from 321 | 322 | cache_redis 323 | 324 | 325 | 326 | 327 | 328 | 329 | seconds 330 | 331 | 0.005 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | http_version: 341 | recorded_at: Sun, 04 Nov 2012 17:12:00 GMT 342 | recorded_with: VCR 2.3.0 343 | -------------------------------------------------------------------------------- /spec/fixtures/http/log_in.yml: -------------------------------------------------------------------------------- 1 | --- 2 | http_interactions: 3 | - request: 4 | method: post 5 | uri: http://api.opensubtitles.org/xml-rpc 6 | body: 7 | string: | 8 | LogInengOS Test User Agent 9 | 10 | headers: 11 | Accept: 12 | - "*/*" 13 | Content-Length: 14 | - "304" 15 | User-Agent: 16 | - XMLRPC::Client (Ruby 1.8.7) 17 | Content-Type: 18 | - text/xml; charset=utf-8 19 | Connection: 20 | - keep-alive 21 | response: 22 | status: 23 | code: 200 24 | message: OK 25 | headers: 26 | X-Cache: 27 | - MISS 28 | Age: 29 | - "0" 30 | X-Cache-Backend: 31 | - www 32 | Cache-Control: 33 | - no-store, no-cache, must-revalidate, post-check=0, pre-check=0 34 | Set-Cookie: 35 | - PHPSESSID=qtqkphpa0us78eikqtdtg4jic7; path=/ 36 | Pragma: 37 | - no-cache 38 | Vary: 39 | - Accept-Encoding 40 | Expires: 41 | - Thu, 19 Nov 1981 08:52:00 GMT 42 | Content-Length: 43 | - "503" 44 | Content-Type: 45 | - text/xml 46 | Connection: 47 | - keep-alive 48 | Accept-Ranges: 49 | - bytes 50 | Date: 51 | - Sun, 04 Nov 2012 17:11:33 GMT 52 | body: 53 | string: | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | token 62 | 63 | qtqkphpa0us78eikqtdtg4jic7 64 | 65 | 66 | 67 | status 68 | 69 | 200 OK 70 | 71 | 72 | 73 | seconds 74 | 75 | 0.01 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | http_version: 85 | recorded_at: Sun, 04 Nov 2012 17:11:33 GMT 86 | recorded_with: VCR 2.3.0 87 | -------------------------------------------------------------------------------- /spec/fixtures/http/log_out.yml: -------------------------------------------------------------------------------- 1 | --- 2 | http_interactions: 3 | - request: 4 | method: post 5 | uri: http://api.opensubtitles.org/xml-rpc 6 | body: 7 | string: | 8 | LogOutqtqkphpa0us78eikqtdtg4jic7 9 | 10 | headers: 11 | Accept: 12 | - "*/*" 13 | Cookie: 14 | - PHPSESSID=qtqkphpa0us78eikqtdtg4jic7 15 | Content-Length: 16 | - "169" 17 | User-Agent: 18 | - XMLRPC::Client (Ruby 1.8.7) 19 | Content-Type: 20 | - text/xml; charset=utf-8 21 | Connection: 22 | - keep-alive 23 | response: 24 | status: 25 | code: 200 26 | message: OK 27 | headers: 28 | X-Cache: 29 | - MISS 30 | Age: 31 | - "0" 32 | X-Cache-Backend: 33 | - www 34 | Vary: 35 | - Accept-Encoding 36 | Content-Length: 37 | - "326" 38 | Content-Type: 39 | - text/xml 40 | Connection: 41 | - keep-alive 42 | Accept-Ranges: 43 | - bytes 44 | Date: 45 | - Sun, 04 Nov 2012 17:11:35 GMT 46 | body: 47 | string: |- 48 | 49 | 50 | 51 | 52 | 53 | 54 | status 55 | 200 OK 56 | 57 | 58 | seconds 59 | 0.001 60 | 61 | 62 | 63 | 64 | 65 | 66 | http_version: 67 | recorded_at: Sun, 04 Nov 2012 17:11:35 GMT 68 | recorded_with: VCR 2.3.0 69 | -------------------------------------------------------------------------------- /spec/fixtures/http/search_imdb.yml: -------------------------------------------------------------------------------- 1 | --- 2 | http_interactions: 3 | - request: 4 | method: post 5 | uri: http://api.opensubtitles.org/xml-rpc 6 | body: 7 | string: | 8 | SearchMoviesOnIMDBqtqkphpa0us78eikqtdtg4jic7Troy 9 | 10 | headers: 11 | Accept: 12 | - "*/*" 13 | Cookie: 14 | - PHPSESSID=qtqkphpa0us78eikqtdtg4jic7 15 | Content-Length: 16 | - "232" 17 | User-Agent: 18 | - XMLRPC::Client (Ruby 1.8.7) 19 | Content-Type: 20 | - text/xml; charset=utf-8 21 | Connection: 22 | - keep-alive 23 | response: 24 | status: 25 | code: 200 26 | message: OK 27 | headers: 28 | X-Cache: 29 | - MISS 30 | Age: 31 | - "0" 32 | X-Cache-Backend: 33 | - www 34 | Cache-Control: 35 | - no-store, no-cache, must-revalidate, post-check=0, pre-check=0 36 | Set-Cookie: 37 | - PHPSESSID=qtqkphpa0us78eikqtdtg4jic7; path=/ 38 | Pragma: 39 | - no-cache 40 | Expires: 41 | - Thu, 19 Nov 1981 08:52:00 GMT 42 | Content-Length: 43 | - "17279" 44 | Content-Type: 45 | - text/xml 46 | Connection: 47 | - keep-alive 48 | Accept-Ranges: 49 | - bytes 50 | Date: 51 | - Sun, 04 Nov 2012 17:11:59 GMT 52 | body: 53 | string: | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | status 62 | 63 | 200 OK 64 | 65 | 66 | 67 | data 68 | 69 | 70 | 71 | 72 | 73 | 74 | id 75 | 76 | 0332452 77 | 78 | 79 | 80 | title 81 | 82 | Troy (2004) Photos ( 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | id 91 | 92 | 1126490 93 | 94 | 95 | 96 | title 97 | 98 | Call Me Troy (2007) 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | id 107 | 108 | 0431721 109 | 110 | 111 | 112 | title 113 | 114 | Denied (2004) aka "Troy Denied" - Canada (English title) (working title) 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | id 123 | 124 | 2287360 125 | 126 | 127 | 128 | title 129 | 130 | A Kid Called Troy (1993) 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | id 139 | 140 | 0059262 141 | 142 | 143 | 144 | title 145 | 146 | Hercules and the Princess of Troy (1965) (TV) aka "Hercules vs. the Sea Monster" - 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | id 155 | 156 | 0768710 157 | 158 | 159 | 160 | title 161 | 162 | The Women of Troy (2006) (V) 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | id 171 | 172 | 0484846 173 | 174 | 175 | 176 | title 177 | 178 | Helen of Troy (2005) (TV) aka "I oraia Eleni" - Greece (transliterated ISO-LATIN-1 title) 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | id 187 | 188 | 0422707 189 | 190 | 191 | 192 | title 193 | 194 | The Making of 'Troy' (2004) (TV) aka "Näin tehtiin elokuva Troija" - Finland 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | id 203 | 204 | 0462049 205 | 206 | 207 | 208 | title 209 | 210 | The True Story of Troy (2004) (TV) 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | id 219 | 220 | 0439021 221 | 222 | 223 | 224 | title 225 | 226 | Troy: From Ruins to Reality (2005) (V) 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | id 235 | 236 | 0439022 237 | 238 | 239 | 240 | title 241 | 242 | Troy: In the Thick of Battle (2005) (V) 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | id 251 | 252 | 0446541 253 | 254 | 255 | 256 | title 257 | 258 | Beyond the Movie: Troy (2004) (TV) 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | id 267 | 268 | 0830492 269 | 270 | 271 | 272 | title 273 | 274 | "The Troy Cory Evening Show" (1974) (TV series) aka "The Troy Cory Show" - USA (alternative title) 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | id 283 | 284 | 0439020 285 | 286 | 287 | 288 | title 289 | 290 | Troy: An Effects Odyssey (2004) (V) 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | id 299 | 300 | 0770821 301 | 302 | 303 | 304 | title 305 | 306 | Troy: The Passion of Helen (2004) (TV) 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | id 315 | 316 | 0409399 317 | 318 | 319 | 320 | title 321 | 322 | Troy: The True Story of Love, Power, Honor & the Pursuit of Glory (2004) (V) 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | id 331 | 332 | 1955057 333 | 334 | 335 | 336 | title 337 | 338 | Warriors: Legends of Troy (2011) (VG) 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | id 347 | 348 | 2302499 349 | 350 | 351 | 352 | title 353 | 354 | A Life in the Balance: Examining the Troy Davis Case (2011) (V) 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | id 363 | 364 | 1008665 365 | 366 | 367 | 368 | title 369 | 370 | Battle for Troy (2004) (VG) 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | id 379 | 380 | 2148889 381 | 382 | 383 | 384 | title 385 | 386 | Chillerama Presents: Anton Troy, the Man Behind the Beast (2011) 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | id 395 | 396 | 1575549 397 | 398 | 399 | 400 | title 401 | 402 | Forgiving Troy: The Documentary (2009) 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | id 411 | 412 | 1918830 413 | 414 | 415 | 416 | title 417 | 418 | From Silence: Troy Donockley & Dave Bainbridge (2006) (TV) 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | id 427 | 428 | 0473990 429 | 430 | 431 | 432 | title 433 | 434 | Helene of Troy, N.Y. (1927) 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | id 443 | 444 | 1315952 445 | 446 | 447 | 448 | title 449 | 450 | Helen of Troy (1917) 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | id 459 | 460 | 0014140 461 | 462 | 463 | 464 | title 465 | 466 | How Troy Was Collared (1923) 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | id 475 | 476 | 0893352 477 | 478 | 479 | 480 | title 481 | 482 | Model Workout with Troy Warwell (2006) (V) 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | id 491 | 492 | 2034066 493 | 494 | 495 | 496 | title 497 | 498 | North Troy Roughcut (2010) 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | id 507 | 508 | 2336401 509 | 510 | 511 | 512 | title 513 | 514 | Odysseus: The Jetman King of Ithaca's Journey to Troy (2012) 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | id 523 | 524 | 1570652 525 | 526 | 527 | 528 | title 529 | 530 | O kaimos tis Oraias Elenis - Polemos i erotas? (2005) aka "The Yearning of Troy Helen - War or Love?" - International (English title) 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | id 539 | 540 | 0044044 541 | 542 | 543 | 544 | title 545 | 546 | Sköna Helena (1951) aka "Helen of Troy" - International (English title) aka "Kaunis Helena" - Finland 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | id 555 | 556 | 1829039 557 | 558 | 559 | 560 | title 561 | 562 | The Epic of Troy Knight (2015) 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | id 571 | 572 | 1129385 573 | 574 | 575 | 576 | title 577 | 578 | The Molders of Troy (1980) (TV) 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | id 587 | 588 | 1022880 589 | 590 | 591 | 592 | title 593 | 594 | The Night They Invented Troy Donahue (2008) 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | id 603 | 604 | 0224296 605 | 606 | 607 | 608 | title 609 | 610 | The Trolley at East Troy (1986) 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | id 619 | 620 | 2398664 621 | 622 | 623 | 624 | title 625 | 626 | "The Troy Rawlings Show" (2011) (TV series) 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | id 635 | 636 | 1670355 637 | 638 | 639 | 640 | title 641 | 642 | The Troy Shawn Welcome Story (2010) 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | id 651 | 652 | 2260927 653 | 654 | 655 | 656 | title 657 | 658 | "Troy Butcher vs. the World" (2011) (TV series) 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | id 667 | 668 | 2426976 669 | 670 | 671 | 672 | title 673 | 674 | Troy Kallmann's: The Apartment (2012) 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | id 683 | 684 | 2266887 685 | 686 | 687 | 688 | title 689 | 690 | Troy: Naked Boys Behind Bars, Sing! (2011) 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | id 699 | 700 | 2148676 701 | 702 | 703 | 704 | title 705 | 706 | Troy Speaks the Truth (2012) 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | id 715 | 716 | 2152728 717 | 718 | 719 | 720 | title 721 | 722 | Women of Troy (1958) (TV) 723 | 724 | 725 | 726 | 727 | 728 | 729 | 730 | id 731 | 732 | 1996306680 733 | 734 | 735 | 736 | title 737 | 738 | Troy - Myth Or Reality (2004) 739 | 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | seconds 749 | 750 | 0.829 751 | 752 | 753 | 754 | 755 | 756 | 757 | 758 | 759 | http_version: 760 | recorded_at: Sun, 04 Nov 2012 17:11:59 GMT 761 | recorded_with: VCR 2.3.0 762 | -------------------------------------------------------------------------------- /spec/fixtures/http/search_subtitles_for_himym.yml: -------------------------------------------------------------------------------- 1 | --- 2 | http_interactions: 3 | - request: 4 | method: post 5 | uri: http://api.opensubtitles.org/xml-rpc 6 | body: 7 | string: | 8 | SearchSubtitlesqtqkphpa0us78eikqtdtg4jic7moviehashbd71526264fd8bd9moviebytesize183406990sublanguageidfre 9 | 10 | headers: 11 | Accept: 12 | - "*/*" 13 | Cookie: 14 | - PHPSESSID=qtqkphpa0us78eikqtdtg4jic7 15 | Content-Length: 16 | - "517" 17 | User-Agent: 18 | - XMLRPC::Client (Ruby 1.8.7) 19 | Content-Type: 20 | - text/xml; charset=utf-8 21 | Connection: 22 | - keep-alive 23 | response: 24 | status: 25 | code: 200 26 | message: OK 27 | headers: 28 | X-Cache: 29 | - MISS 30 | Age: 31 | - "0" 32 | X-Cache-Backend: 33 | - www 34 | Cache-Control: 35 | - no-store, no-cache, must-revalidate, post-check=0, pre-check=0 36 | Set-Cookie: 37 | - PHPSESSID=qtqkphpa0us78eikqtdtg4jic7; path=/ 38 | Pragma: 39 | - no-cache 40 | Expires: 41 | - Thu, 19 Nov 1981 08:52:00 GMT 42 | Content-Length: 43 | - "29213" 44 | Content-Type: 45 | - text/xml 46 | Connection: 47 | - keep-alive 48 | Accept-Ranges: 49 | - bytes 50 | Date: 51 | - Sun, 04 Nov 2012 17:11:45 GMT 52 | body: 53 | string: | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | status 62 | 63 | 200 OK 64 | 65 | 66 | 67 | data 68 | 69 | 70 | 71 | 72 | 73 | 74 | MatchedBy 75 | 76 | moviehash 77 | 78 | 79 | 80 | IDSubMovieFile 81 | 82 | 117533 83 | 84 | 85 | 86 | MovieHash 87 | 88 | bd71526264fd8bd9 89 | 90 | 91 | 92 | MovieByteSize 93 | 94 | 183406990 95 | 96 | 97 | 98 | MovieTimeMS 99 | 100 | 1287000 101 | 102 | 103 | 104 | IDSubtitleFile 105 | 106 | 1951739419 107 | 108 | 109 | 110 | SubFileName 111 | 112 | How I Met Your Mother - 2x22 - Something Blue.srt 113 | 114 | 115 | 116 | SubActualCD 117 | 118 | 1 119 | 120 | 121 | 122 | SubSize 123 | 124 | 29532 125 | 126 | 127 | 128 | SubHash 129 | 130 | 49ba29341936f44b67f87abe58846e57 131 | 132 | 133 | 134 | IDSubtitle 135 | 136 | 4361038 137 | 138 | 139 | 140 | UserID 141 | 142 | 994714 143 | 144 | 145 | 146 | SubLanguageID 147 | 148 | fre 149 | 150 | 151 | 152 | SubFormat 153 | 154 | srt 155 | 156 | 157 | 158 | SubSumCD 159 | 160 | 1 161 | 162 | 163 | 164 | SubAuthorComment 165 | 166 | 167 | 168 | 169 | 170 | SubAddDate 171 | 172 | 2008-01-31 17:15:39 173 | 174 | 175 | 176 | SubBad 177 | 178 | 0 179 | 180 | 181 | 182 | SubRating 183 | 184 | 10.0 185 | 186 | 187 | 188 | SubDownloadsCnt 189 | 190 | 1753 191 | 192 | 193 | 194 | MovieReleaseName 195 | 196 | How I Met Your Mother - Season 2 197 | 198 | 199 | 200 | IDMovie 201 | 202 | 90865 203 | 204 | 205 | 206 | IDMovieImdb 207 | 208 | 1017766 209 | 210 | 211 | 212 | MovieName 213 | 214 | "How I Met Your Mother" Something Blue 215 | 216 | 217 | 218 | MovieNameEng 219 | 220 | 221 | 222 | 223 | 224 | MovieYear 225 | 226 | 2007 227 | 228 | 229 | 230 | MovieImdbRating 231 | 232 | 8.6 233 | 234 | 235 | 236 | SubFeatured 237 | 238 | 0 239 | 240 | 241 | 242 | UserNickName 243 | 244 | jlauwers 245 | 246 | 247 | 248 | ISO639 249 | 250 | fr 251 | 252 | 253 | 254 | LanguageName 255 | 256 | French 257 | 258 | 259 | 260 | SubComments 261 | 262 | 0 263 | 264 | 265 | 266 | SubHearingImpaired 267 | 268 | 0 269 | 270 | 271 | 272 | UserRank 273 | 274 | gold member 275 | 276 | 277 | 278 | SeriesSeason 279 | 280 | 2 281 | 282 | 283 | 284 | SeriesEpisode 285 | 286 | 22 287 | 288 | 289 | 290 | MovieKind 291 | 292 | episode 293 | 294 | 295 | 296 | QueryParameters 297 | 298 | 299 | 300 | moviehash 301 | 302 | bd71526264fd8bd9 303 | 304 | 305 | 306 | moviebytesize 307 | 308 | 183406990 309 | 310 | 311 | 312 | sublanguageid 313 | 314 | fre 315 | 316 | 317 | 318 | 319 | 320 | 321 | QueryNumber 322 | 323 | 0 324 | 325 | 326 | 327 | SubDownloadLink 328 | 329 | http://dl.opensubtitles.org/en/download/filead/1951739419.gz 330 | 331 | 332 | 333 | ZipDownloadLink 334 | 335 | http://dl.opensubtitles.org/en/download/subad/4361038 336 | 337 | 338 | 339 | SubtitlesLink 340 | 341 | http://www.opensubtitles.org/en/subtitles/4361038/how-i-met-your-mother-something-blue-fr 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | MatchedBy 350 | 351 | moviehash 352 | 353 | 354 | 355 | IDSubMovieFile 356 | 357 | 872779 358 | 359 | 360 | 361 | MovieHash 362 | 363 | bd71526264fd8bd9 364 | 365 | 366 | 367 | MovieByteSize 368 | 369 | 183406990 370 | 371 | 372 | 373 | MovieTimeMS 374 | 375 | 0 376 | 377 | 378 | 379 | IDSubtitleFile 380 | 381 | 1952337295 382 | 383 | 384 | 385 | SubFileName 386 | 387 | How I Met Your Mother S02E22 - Something Blue.xor.VF.srt 388 | 389 | 390 | 391 | SubActualCD 392 | 393 | 1 394 | 395 | 396 | 397 | SubSize 398 | 399 | 32467 400 | 401 | 402 | 403 | SubHash 404 | 405 | 981146aec08be3d6d8709641d782f5da 406 | 407 | 408 | 409 | IDSubtitle 410 | 411 | 3687427 412 | 413 | 414 | 415 | UserID 416 | 417 | 1253306 418 | 419 | 420 | 421 | SubLanguageID 422 | 423 | fre 424 | 425 | 426 | 427 | SubFormat 428 | 429 | srt 430 | 431 | 432 | 433 | SubSumCD 434 | 435 | 1 436 | 437 | 438 | 439 | SubAuthorComment 440 | 441 | 442 | 443 | 444 | 445 | SubAddDate 446 | 447 | 2010-06-09 20:10:11 448 | 449 | 450 | 451 | SubBad 452 | 453 | 0 454 | 455 | 456 | 457 | SubRating 458 | 459 | 0.0 460 | 461 | 462 | 463 | SubDownloadsCnt 464 | 465 | 333 466 | 467 | 468 | 469 | MovieReleaseName 470 | 471 | How I Met Your Mother S02E22 - Something Blue.xor.VF 472 | 473 | 474 | 475 | IDMovie 476 | 477 | 90865 478 | 479 | 480 | 481 | IDMovieImdb 482 | 483 | 1017766 484 | 485 | 486 | 487 | MovieName 488 | 489 | "How I Met Your Mother" Something Blue 490 | 491 | 492 | 493 | MovieNameEng 494 | 495 | 496 | 497 | 498 | 499 | MovieYear 500 | 501 | 2007 502 | 503 | 504 | 505 | MovieImdbRating 506 | 507 | 8.6 508 | 509 | 510 | 511 | SubFeatured 512 | 513 | 0 514 | 515 | 516 | 517 | UserNickName 518 | 519 | omarf1 520 | 521 | 522 | 523 | ISO639 524 | 525 | fr 526 | 527 | 528 | 529 | LanguageName 530 | 531 | French 532 | 533 | 534 | 535 | SubComments 536 | 537 | 0 538 | 539 | 540 | 541 | SubHearingImpaired 542 | 543 | 0 544 | 545 | 546 | 547 | UserRank 548 | 549 | gold member 550 | 551 | 552 | 553 | SeriesSeason 554 | 555 | 2 556 | 557 | 558 | 559 | SeriesEpisode 560 | 561 | 22 562 | 563 | 564 | 565 | MovieKind 566 | 567 | episode 568 | 569 | 570 | 571 | QueryParameters 572 | 573 | 574 | 575 | moviehash 576 | 577 | bd71526264fd8bd9 578 | 579 | 580 | 581 | moviebytesize 582 | 583 | 183406990 584 | 585 | 586 | 587 | sublanguageid 588 | 589 | fre 590 | 591 | 592 | 593 | 594 | 595 | 596 | QueryNumber 597 | 598 | 0 599 | 600 | 601 | 602 | SubDownloadLink 603 | 604 | http://dl.opensubtitles.org/en/download/filead/1952337295.gz 605 | 606 | 607 | 608 | ZipDownloadLink 609 | 610 | http://dl.opensubtitles.org/en/download/subad/3687427 611 | 612 | 613 | 614 | SubtitlesLink 615 | 616 | http://www.opensubtitles.org/en/subtitles/3687427/how-i-met-your-mother-something-blue-fr 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | MatchedBy 625 | 626 | moviehash 627 | 628 | 629 | 630 | IDSubMovieFile 631 | 632 | 1590113 633 | 634 | 635 | 636 | MovieHash 637 | 638 | bd71526264fd8bd9 639 | 640 | 641 | 642 | MovieByteSize 643 | 644 | 183406990 645 | 646 | 647 | 648 | MovieTimeMS 649 | 650 | 0 651 | 652 | 653 | 654 | IDSubtitleFile 655 | 656 | 1952188857 657 | 658 | 659 | 660 | SubFileName 661 | 662 | How I Met Your Mother - 2x22 - Something Blue.srt 663 | 664 | 665 | 666 | SubActualCD 667 | 668 | 1 669 | 670 | 671 | 672 | SubSize 673 | 674 | 24762 675 | 676 | 677 | 678 | SubHash 679 | 680 | 9d51153ba5ec4b726ab5c6c983d4d93c 681 | 682 | 683 | 684 | IDSubtitle 685 | 686 | 4328245 687 | 688 | 689 | 690 | UserID 691 | 692 | 845334 693 | 694 | 695 | 696 | SubLanguageID 697 | 698 | fre 699 | 700 | 701 | 702 | SubFormat 703 | 704 | srt 705 | 706 | 707 | 708 | SubSumCD 709 | 710 | 1 711 | 712 | 713 | 714 | SubAuthorComment 715 | 716 | 717 | 718 | 719 | 720 | SubAddDate 721 | 722 | 2009-09-14 20:03:22 723 | 724 | 725 | 726 | SubBad 727 | 728 | 0 729 | 730 | 731 | 732 | SubRating 733 | 734 | 0.0 735 | 736 | 737 | 738 | SubDownloadsCnt 739 | 740 | 480 741 | 742 | 743 | 744 | MovieReleaseName 745 | 746 | How I Met Your Mother Season 2 747 | 748 | 749 | 750 | IDMovie 751 | 752 | 90865 753 | 754 | 755 | 756 | IDMovieImdb 757 | 758 | 1017766 759 | 760 | 761 | 762 | MovieName 763 | 764 | "How I Met Your Mother" Something Blue 765 | 766 | 767 | 768 | MovieNameEng 769 | 770 | 771 | 772 | 773 | 774 | MovieYear 775 | 776 | 2007 777 | 778 | 779 | 780 | MovieImdbRating 781 | 782 | 8.6 783 | 784 | 785 | 786 | SubFeatured 787 | 788 | 0 789 | 790 | 791 | 792 | UserNickName 793 | 794 | ZeRoCooL64 795 | 796 | 797 | 798 | ISO639 799 | 800 | fr 801 | 802 | 803 | 804 | LanguageName 805 | 806 | French 807 | 808 | 809 | 810 | SubComments 811 | 812 | 0 813 | 814 | 815 | 816 | SubHearingImpaired 817 | 818 | 0 819 | 820 | 821 | 822 | UserRank 823 | 824 | bronze member 825 | 826 | 827 | 828 | SeriesSeason 829 | 830 | 2 831 | 832 | 833 | 834 | SeriesEpisode 835 | 836 | 22 837 | 838 | 839 | 840 | MovieKind 841 | 842 | episode 843 | 844 | 845 | 846 | QueryParameters 847 | 848 | 849 | 850 | moviehash 851 | 852 | bd71526264fd8bd9 853 | 854 | 855 | 856 | moviebytesize 857 | 858 | 183406990 859 | 860 | 861 | 862 | sublanguageid 863 | 864 | fre 865 | 866 | 867 | 868 | 869 | 870 | 871 | QueryNumber 872 | 873 | 0 874 | 875 | 876 | 877 | SubDownloadLink 878 | 879 | http://dl.opensubtitles.org/en/download/filead/1952188857.gz 880 | 881 | 882 | 883 | ZipDownloadLink 884 | 885 | http://dl.opensubtitles.org/en/download/subad/4328245 886 | 887 | 888 | 889 | SubtitlesLink 890 | 891 | http://www.opensubtitles.org/en/subtitles/4328245/how-i-met-your-mother-something-blue-fr 892 | 893 | 894 | 895 | 896 | 897 | 898 | 899 | MatchedBy 900 | 901 | moviehash 902 | 903 | 904 | 905 | IDSubMovieFile 906 | 907 | 1945333 908 | 909 | 910 | 911 | MovieHash 912 | 913 | bd71526264fd8bd9 914 | 915 | 916 | 917 | MovieByteSize 918 | 919 | 183406990 920 | 921 | 922 | 923 | MovieTimeMS 924 | 925 | 0 926 | 927 | 928 | 929 | IDSubtitleFile 930 | 931 | 1952693786 932 | 933 | 934 | 935 | SubFileName 936 | 937 | How I Met Your Mother - 2x22 - Something Blue.fr.srt 938 | 939 | 940 | 941 | SubActualCD 942 | 943 | 1 944 | 945 | 946 | 947 | SubSize 948 | 949 | 32684 950 | 951 | 952 | 953 | SubHash 954 | 955 | 1f0d06698c8b632edb89e0f72f36e7c1 956 | 957 | 958 | 959 | IDSubtitle 960 | 961 | 4019688 962 | 963 | 964 | 965 | UserID 966 | 967 | 1017601 968 | 969 | 970 | 971 | SubLanguageID 972 | 973 | fre 974 | 975 | 976 | 977 | SubFormat 978 | 979 | srt 980 | 981 | 982 | 983 | SubSumCD 984 | 985 | 1 986 | 987 | 988 | 989 | SubAuthorComment 990 | 991 | 992 | 993 | 994 | 995 | SubAddDate 996 | 997 | 2010-12-23 12:26:24 998 | 999 | 1000 | 1001 | SubBad 1002 | 1003 | 0 1004 | 1005 | 1006 | 1007 | SubRating 1008 | 1009 | 0.0 1010 | 1011 | 1012 | 1013 | SubDownloadsCnt 1014 | 1015 | 149 1016 | 1017 | 1018 | 1019 | MovieReleaseName 1020 | 1021 | How I Met Your Mother - 2x22 - Something Blue.fr 1022 | 1023 | 1024 | 1025 | IDMovie 1026 | 1027 | 90865 1028 | 1029 | 1030 | 1031 | IDMovieImdb 1032 | 1033 | 1017766 1034 | 1035 | 1036 | 1037 | MovieName 1038 | 1039 | "How I Met Your Mother" Something Blue 1040 | 1041 | 1042 | 1043 | MovieNameEng 1044 | 1045 | 1046 | 1047 | 1048 | 1049 | MovieYear 1050 | 1051 | 2007 1052 | 1053 | 1054 | 1055 | MovieImdbRating 1056 | 1057 | 8.6 1058 | 1059 | 1060 | 1061 | SubFeatured 1062 | 1063 | 0 1064 | 1065 | 1066 | 1067 | UserNickName 1068 | 1069 | hrxfab 1070 | 1071 | 1072 | 1073 | ISO639 1074 | 1075 | fr 1076 | 1077 | 1078 | 1079 | LanguageName 1080 | 1081 | French 1082 | 1083 | 1084 | 1085 | SubComments 1086 | 1087 | 0 1088 | 1089 | 1090 | 1091 | SubHearingImpaired 1092 | 1093 | 0 1094 | 1095 | 1096 | 1097 | UserRank 1098 | 1099 | gold member 1100 | 1101 | 1102 | 1103 | SeriesSeason 1104 | 1105 | 2 1106 | 1107 | 1108 | 1109 | SeriesEpisode 1110 | 1111 | 22 1112 | 1113 | 1114 | 1115 | MovieKind 1116 | 1117 | episode 1118 | 1119 | 1120 | 1121 | QueryParameters 1122 | 1123 | 1124 | 1125 | moviehash 1126 | 1127 | bd71526264fd8bd9 1128 | 1129 | 1130 | 1131 | moviebytesize 1132 | 1133 | 183406990 1134 | 1135 | 1136 | 1137 | sublanguageid 1138 | 1139 | fre 1140 | 1141 | 1142 | 1143 | 1144 | 1145 | 1146 | QueryNumber 1147 | 1148 | 0 1149 | 1150 | 1151 | 1152 | SubDownloadLink 1153 | 1154 | http://dl.opensubtitles.org/en/download/filead/1952693786.gz 1155 | 1156 | 1157 | 1158 | ZipDownloadLink 1159 | 1160 | http://dl.opensubtitles.org/en/download/subad/4019688 1161 | 1162 | 1163 | 1164 | SubtitlesLink 1165 | 1166 | http://www.opensubtitles.org/en/subtitles/4019688/how-i-met-your-mother-something-blue-fr 1167 | 1168 | 1169 | 1170 | 1171 | 1172 | 1173 | 1174 | 1175 | 1176 | seconds 1177 | 1178 | 0.176 1179 | 1180 | 1181 | 1182 | 1183 | 1184 | 1185 | 1186 | 1187 | http_version: 1188 | recorded_at: Sun, 04 Nov 2012 17:11:45 GMT 1189 | recorded_with: VCR 2.3.0 1190 | -------------------------------------------------------------------------------- /spec/fixtures/http/server_info.yml: -------------------------------------------------------------------------------- 1 | --- 2 | http_interactions: 3 | - request: 4 | method: post 5 | uri: http://api.opensubtitles.org/xml-rpc 6 | body: 7 | string: | 8 | ServerInfo 9 | 10 | headers: 11 | Accept: 12 | - "*/*" 13 | Content-Length: 14 | - "92" 15 | User-Agent: 16 | - XMLRPC::Client (Ruby 1.8.7) 17 | Content-Type: 18 | - text/xml; charset=utf-8 19 | Connection: 20 | - keep-alive 21 | response: 22 | status: 23 | code: 200 24 | message: OK 25 | headers: 26 | X-Cache: 27 | - MISS 28 | Age: 29 | - "0" 30 | X-Cache-Backend: 31 | - www 32 | Content-Length: 33 | - "9664" 34 | Content-Type: 35 | - text/xml 36 | Connection: 37 | - keep-alive 38 | Accept-Ranges: 39 | - bytes 40 | Date: 41 | - Sun, 04 Nov 2012 17:11:32 GMT 42 | body: 43 | string: | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | xmlrpc_version 52 | 53 | 0.1 54 | 55 | 56 | 57 | xmlrpc_url 58 | 59 | http://api.opensubtitles.org/xml-rpc 60 | 61 | 62 | 63 | application 64 | 65 | OpenSuber v0.2 66 | 67 | 68 | 69 | contact 70 | 71 | admin@opensubtitles.org 72 | 73 | 74 | 75 | website_url 76 | 77 | http://www.opensubtitles.org 78 | 79 | 80 | 81 | users_online_total 82 | 83 | 13570 84 | 85 | 86 | 87 | users_online_program 88 | 89 | 10099 90 | 91 | 92 | 93 | users_loggedin 94 | 95 | 127 96 | 97 | 98 | 99 | users_max_alltime 100 | 101 | 27449 102 | 103 | 104 | 105 | users_registered 106 | 107 | 1025281 108 | 109 | 110 | 111 | subs_downloads 112 | 113 | 766307871 114 | 115 | 116 | 117 | subs_subtitle_files 118 | 119 | 1864635 120 | 121 | 122 | 123 | movies_total 124 | 125 | 136467 126 | 127 | 128 | 129 | movies_aka 130 | 131 | 277764 132 | 133 | 134 | 135 | total_subtitles_languages 136 | 137 | 61 138 | 139 | 140 | 141 | last_update_strings 142 | 143 | 144 | 145 | ar 146 | 147 | 2007-02-03 21:36:14 148 | 149 | 150 | 151 | bg 152 | 153 | 2007-02-03 21:36:14 154 | 155 | 156 | 157 | ca 158 | 159 | 2009-07-06 06:20:41 160 | 161 | 162 | 163 | cs 164 | 165 | 2007-02-03 21:36:15 166 | 167 | 168 | 169 | da 170 | 171 | 2007-02-16 14:07:42 172 | 173 | 174 | 175 | de 176 | 177 | 2007-02-03 21:36:15 178 | 179 | 180 | 181 | el 182 | 183 | 2007-02-03 21:36:17 184 | 185 | 186 | 187 | en 188 | 189 | 2007-02-03 21:36:14 190 | 191 | 192 | 193 | es 194 | 195 | 2007-02-03 21:36:21 196 | 197 | 198 | 199 | et 200 | 201 | 2007-05-07 20:43:40 202 | 203 | 204 | 205 | eu 206 | 207 | 2011-08-28 08:37:00 208 | 209 | 210 | 211 | fa 212 | 213 | 2007-02-03 21:36:16 214 | 215 | 216 | 217 | fi 218 | 219 | 2007-02-03 21:36:16 220 | 221 | 222 | 223 | fr 224 | 225 | 2007-02-03 21:36:16 226 | 227 | 228 | 229 | gl 230 | 231 | 2007-10-11 16:23:40 232 | 233 | 234 | 235 | he 236 | 237 | 2007-02-03 21:36:17 238 | 239 | 240 | 241 | hi 242 | 243 | 2011-11-07 09:54:58 244 | 245 | 246 | 247 | hr 248 | 249 | 2007-02-04 11:05:51 250 | 251 | 252 | 253 | hu 254 | 255 | 2007-02-03 21:36:17 256 | 257 | 258 | 259 | id 260 | 261 | 2007-02-03 21:36:18 262 | 263 | 264 | 265 | is 266 | 267 | 2011-01-04 20:33:08 268 | 269 | 270 | 271 | it 272 | 273 | 2007-02-03 21:36:18 274 | 275 | 276 | 277 | ja 278 | 279 | 2007-02-04 11:05:11 280 | 281 | 282 | 283 | ka 284 | 285 | 2007-06-09 17:08:29 286 | 287 | 288 | 289 | km 290 | 291 | 2011-12-31 03:57:52 292 | 293 | 294 | 295 | ko 296 | 297 | 2007-02-04 11:05:16 298 | 299 | 300 | 301 | mk 302 | 303 | 2007-12-06 10:45:07 304 | 305 | 306 | 307 | ms 308 | 309 | 2009-04-18 09:08:07 310 | 311 | 312 | 313 | nl 314 | 315 | 2007-02-03 21:36:15 316 | 317 | 318 | 319 | no 320 | 321 | 2007-02-03 21:36:18 322 | 323 | 324 | 325 | oc 326 | 327 | 2008-12-16 12:56:29 328 | 329 | 330 | 331 | pb 332 | 333 | 2007-02-03 21:36:19 334 | 335 | 336 | 337 | pl 338 | 339 | 2007-02-03 21:36:19 340 | 341 | 342 | 343 | pt 344 | 345 | 2007-02-03 21:36:19 346 | 347 | 348 | 349 | ro 350 | 351 | 2007-02-03 21:36:20 352 | 353 | 354 | 355 | ru 356 | 357 | 2007-02-03 21:36:20 358 | 359 | 360 | 361 | si 362 | 363 | 2009-08-09 10:06:20 364 | 365 | 366 | 367 | sk 368 | 369 | 2007-02-03 21:36:20 370 | 371 | 372 | 373 | sl 374 | 375 | 2008-08-26 08:39:30 376 | 377 | 378 | 379 | sq 380 | 381 | 2008-03-06 19:11:57 382 | 383 | 384 | 385 | sr 386 | 387 | 2007-09-05 10:16:25 388 | 389 | 390 | 391 | sv 392 | 393 | 2007-02-03 21:36:21 394 | 395 | 396 | 397 | th 398 | 399 | 2007-06-28 10:37:46 400 | 401 | 402 | 403 | tl 404 | 405 | 2009-08-24 16:32:10 406 | 407 | 408 | 409 | tr 410 | 411 | 2007-02-03 21:36:22 412 | 413 | 414 | 415 | uk 416 | 417 | 2010-03-22 10:14:26 418 | 419 | 420 | 421 | vi 422 | 423 | 2007-02-04 11:05:03 424 | 425 | 426 | 427 | zh 428 | 429 | 2007-02-04 11:05:27 430 | 431 | 432 | 433 | 434 | 435 | 436 | download_limits 437 | 438 | 439 | 440 | global_24h_download_limit 441 | 442 | 200 443 | 444 | 445 | 446 | client_ip 447 | 448 | 80.30.33.21 449 | 450 | 451 | 452 | limit_check_by 453 | 454 | user_ip 455 | 456 | 457 | 458 | client_24h_download_count 459 | 460 | 1 461 | 462 | 463 | 464 | client_download_quota 465 | 466 | 199 467 | 468 | 469 | 470 | client_24h_download_limit 471 | 472 | 200 473 | 474 | 475 | 476 | 477 | 478 | 479 | seconds 480 | 481 | 0.149 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | http_version: 491 | recorded_at: Sun, 04 Nov 2012 17:11:32 GMT 492 | recorded_with: VCR 2.3.0 493 | -------------------------------------------------------------------------------- /spec/fixtures/somemovie.avi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byroot/ruby-osdb/bdb5dd03a17e3a5fea6efddaabe4428d762ee3fd/spec/fixtures/somemovie.avi -------------------------------------------------------------------------------- /spec/osdb/language_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') 2 | 3 | describe OSDb::Language do 4 | 5 | describe '.from_locale' do 6 | 7 | describe "simple locale" do 8 | 9 | subject{ OSDb::Language.from_locale('fr') } 10 | 11 | its(:name) { should == 'French' } 12 | 13 | its(:to_iso639_1) { should == 'fr' } 14 | 15 | its(:to_iso639_2b) { should == 'fre' } 16 | 17 | end 18 | 19 | describe "locale with territory" do 20 | 21 | subject{ OSDb::Language.from_locale('en_US') } 22 | 23 | its(:name) { should == 'English (US)' } 24 | 25 | its(:to_iso639_1) { should == 'en' } 26 | 27 | its(:to_iso639_2b) { should == 'eng' } 28 | 29 | end 30 | 31 | describe "locale with territory and encoding" do 32 | 33 | subject{ OSDb::Language.from_locale('es_ES.UTF8') } 34 | 35 | its(:name) { should == 'Spanish (Spain)' } 36 | 37 | its(:to_iso639_1) { should == 'es' } 38 | 39 | its(:to_iso639_2b) { should == 'spa' } 40 | 41 | end 42 | 43 | end 44 | 45 | describe ".from_iso_639_2b" do 46 | 47 | subject{ OSDb::Language.from_iso639_2b('bre') } 48 | 49 | its(:name) { should == 'English (UK)' } 50 | 51 | its(:to_iso639_1) { should == 'en' } 52 | 53 | its(:to_locale) { should == 'en_GB' } 54 | 55 | end 56 | 57 | end 58 | -------------------------------------------------------------------------------- /spec/osdb/movie_file_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') 2 | 3 | describe OSDb::MovieFile do 4 | 5 | subject do 6 | OSDb::MovieFile.new(File.dirname(__FILE__) + '/../fixtures/somemovie.avi') 7 | end 8 | 9 | its(:hash) { should == '243339b48f4e8741' } 10 | its(:name) { should == 'somemovie' } 11 | 12 | describe '#sub_path' do 13 | it 'should only change the extension of the movie' do 14 | movie_file = OSDb::MovieFile.new('directory-with-extension.avi/movie-file.avi', false) 15 | movie_file.sub_path('srt').should == 'directory-with-extension.avi/movie-file.srt' 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /spec/osdb/server_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') 2 | 3 | describe OSDb::Server do 4 | 5 | before :all do 6 | @server = OSDb::Server.new( 7 | :host => 'api.opensubtitles.org', 8 | :path => '/xml-rpc', 9 | :timeout => 60, # OS.org is very very slow .... 10 | :useragent => 'OS Test User Agent' 11 | ) 12 | end 13 | 14 | subject { @server } 15 | 16 | let(:expected_info) do 17 | { 18 | "website_url"=>"http://www.opensubtitles.org", 19 | "contact"=>"admin@opensubtitles.org", 20 | "application"=>"OpenSuber v0.2", 21 | "xmlrpc_version"=>"0.1", 22 | "xmlrpc_url"=>"http://api.opensubtitles.org/xml-rpc" 23 | } 24 | end 25 | 26 | it 'should respond to #info' do 27 | VCR.use_cassette('server_info') do 28 | info = subject.info 29 | expected_info.each do |key, value| 30 | info[key].should == value 31 | end 32 | info['seconds'].should be_a(Float) 33 | info['last_update_strings'].should be_a(Hash) 34 | end 35 | end 36 | 37 | it 'should automatically call #login when token is needed' do 38 | VCR.use_cassette('log_in') do 39 | subject.instance_variable_get('@token').should be_nil 40 | subject.token.should match(/[a-z0-9]{26}/) 41 | subject.instance_variable_get('@token').should == subject.token 42 | end 43 | end 44 | 45 | it 'should clear @login after #logout' do 46 | VCR.use_cassette('log_in') do 47 | subject.token 48 | end 49 | VCR.use_cassette('log_out') do 50 | expect { 51 | subject.logout 52 | }.to change{ subject.instance_variable_get('@token') }.from(instance_of(String)).to(nil) 53 | end 54 | end 55 | 56 | describe "#check_movie_hash" do 57 | 58 | it 'should identify movie' do 59 | VCR.use_cassette('check_movie_hash') do 60 | subject.check_movie_hash('37d0c7d0cfcbe280')['data'].should == { 61 | "37d0c7d0cfcbe280" => { 62 | "MovieYear" => "1996", 63 | "MovieImdbID" => "0117500", 64 | "MovieName" => "The Rock", 65 | "MovieHash" => "37d0c7d0cfcbe280", 66 | "MovieKind" => "movie", 67 | "SeriesSeason" => "0", 68 | "SeriesEpisode" => "0" 69 | } 70 | } 71 | end 72 | end 73 | 74 | end 75 | 76 | describe '#search_subtitles' do 77 | 78 | it 'can search by hash and size' do 79 | VCR.use_cassette('search_subtitles_for_himym') do 80 | subs = subject.search_subtitles(:moviehash => 'bd71526264fd8bd9', :moviebytesize => '183406990', :sublanguageid => 'fre') 81 | subs.should be_a(Array) 82 | subs.length.should >= 2 83 | subs.each do |sub| 84 | sub.language.name.should == 'French' 85 | sub.raw_data['MovieName'].should =~ /How I Met Your Mother/ 86 | end 87 | end 88 | end 89 | 90 | it 'can search by imdbid' do 91 | VCR.use_cassette('search_subtitles_for_the_rock') do 92 | subs = subject.search_subtitles(:imdbid => "0117500", :sublanguageid => 'fre') 93 | subs.should be_a(Array) 94 | subs.length.should >= 1 95 | subs.each do |sub| 96 | sub.language.name.should == 'French' 97 | sub.raw_data['MovieName'].should == 'The Rock' 98 | end 99 | end 100 | end 101 | 102 | end 103 | 104 | describe "#search_imdb" do 105 | it "can search imdb by title" do 106 | VCR.use_cassette('search_imdb') do 107 | imdb = subject.search_imdb(:query => "Troy") 108 | imdb.each do |movie| 109 | movie.title.should =~ /Troy/ 110 | end 111 | end 112 | end 113 | 114 | it "can get the details of a movie from an id" do 115 | VCR.use_cassette('get_imdb_movie_details') do 116 | movie = subject.get_imdb_movie_details('0176415') 117 | movie.title.should == 'El abuelo' 118 | movie.year.should == 1998 119 | end 120 | end 121 | end 122 | 123 | end 124 | -------------------------------------------------------------------------------- /spec/osdb/sub_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') 2 | 3 | describe OSDb::Sub do 4 | 5 | before :each do 6 | @response = { 7 | 'SubFormat' => 'srt', 8 | 'SubDownloadLink' => 'http://example.com/foo.srt.gz', 9 | 'SubRating' => '7.89', 10 | 'SubLanguageID' => 'dut', 11 | 'MovieName' => 'Lock, Stock and Two Smoking Barrels' 12 | } 13 | end 14 | 15 | subject do 16 | OSDb::Sub.new @response 17 | end 18 | 19 | its(:format) { should == 'srt' } 20 | 21 | its(:url) { should be_an(URI::HTTP) } 22 | 23 | its(:language) { should be_a(OSDb::Language) } 24 | 25 | its(:rating) { should == 7.89 } 26 | 27 | its(:movie_name) { should == 'Lock, Stock and Two Smoking Barrels' } 28 | 29 | it 'should be comparable' do 30 | [subject, OSDb::Sub.new(@response.merge('SubRating' => '2.45'))].max.should == subject 31 | end 32 | 33 | end 34 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/../lib/osdb' 2 | require 'rspec' 3 | 4 | require 'webmock/rspec' 5 | require 'vcr' 6 | 7 | RSpec.configure do |c| 8 | c.mock_with :rspec 9 | end 10 | 11 | VCR.configure do |c| 12 | c.cassette_library_dir = 'spec/fixtures/http' 13 | c.hook_into :webmock 14 | end 15 | --------------------------------------------------------------------------------