opensubtitles 0.0.1

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.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +10 -0
  5. data/Gemfile +3 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +50 -0
  8. data/Rakefile +9 -0
  9. data/bin/getsub +157 -0
  10. data/lib/opensubtitles.rb +21 -0
  11. data/lib/opensubtitles/finder.rb +8 -0
  12. data/lib/opensubtitles/finder/first.rb +13 -0
  13. data/lib/opensubtitles/finder/interactive.rb +21 -0
  14. data/lib/opensubtitles/finder/score.rb +13 -0
  15. data/lib/opensubtitles/language.rb +84 -0
  16. data/lib/opensubtitles/movie.rb +16 -0
  17. data/lib/opensubtitles/movie_file.rb +67 -0
  18. data/lib/opensubtitles/search.rb +9 -0
  19. data/lib/opensubtitles/search/imdb.rb +27 -0
  20. data/lib/opensubtitles/search/movie_hash.rb +21 -0
  21. data/lib/opensubtitles/search/name.rb +28 -0
  22. data/lib/opensubtitles/search/path.rb +20 -0
  23. data/lib/opensubtitles/selector.rb +7 -0
  24. data/lib/opensubtitles/selector/format.rb +17 -0
  25. data/lib/opensubtitles/selector/movie.rb +29 -0
  26. data/lib/opensubtitles/server.rb +70 -0
  27. data/lib/opensubtitles/sub.rb +55 -0
  28. data/lib/opensubtitles/subtitle_finder.rb +30 -0
  29. data/lib/opensubtitles/version.rb +3 -0
  30. data/lib/opensubtitles/xmlrpc_monkey_patch.rb +88 -0
  31. data/opensubtitles.gemspec +26 -0
  32. data/spec/fixtures/http/check_movie_hash.yml +225 -0
  33. data/spec/fixtures/http/get_imdb_movie_details.yml +342 -0
  34. data/spec/fixtures/http/log_in.yml +86 -0
  35. data/spec/fixtures/http/log_out.yml +68 -0
  36. data/spec/fixtures/http/search_imdb.yml +761 -0
  37. data/spec/fixtures/http/search_subtitles_for_himym.yml +1189 -0
  38. data/spec/fixtures/http/search_subtitles_for_the_rock.yml +4124 -0
  39. data/spec/fixtures/http/server_info.yml +492 -0
  40. data/spec/fixtures/somemovie.avi +0 -0
  41. data/spec/opensubtitles/language_spec.rb +57 -0
  42. data/spec/opensubtitles/movie_file_spec.rb +18 -0
  43. data/spec/opensubtitles/server_spec.rb +123 -0
  44. data/spec/opensubtitles/sub_spec.rb +33 -0
  45. data/spec/spec_helper.rb +15 -0
  46. metadata +159 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 56636430f2a77e1d25513363f97d20621023c537
4
+ data.tar.gz: 879215ec0a742848a2c1c43b32684742f7761f1c
5
+ SHA512:
6
+ metadata.gz: 971eeb7d6fb8b304b6e687bfe24e39a19d3b463d242b2bd50e7138670a5c72c85c09b674ba39bf012bc392224f038b81f673fcf0956e5c28168064de78837101
7
+ data.tar.gz: 1c93a7f15b5f4eb5639eadf77a23c9c64e2c57507542af3609dbfcb822a1bc93e3bec4d8b2d385fc8aab0b32c648adcec51f94d898d6881bc822056c954916ea
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,10 @@
1
+ rvm:
2
+ - 1.9.3
3
+ # - 2.0.1
4
+ - 2.1.1
5
+ - 2.2.1
6
+ - 2.2.3
7
+ - rbx
8
+ - jruby
9
+ # - ree
10
+
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
@@ -0,0 +1,22 @@
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.
@@ -0,0 +1,50 @@
1
+ # Opensubtitles
2
+
3
+ Client library for the [Opensubtitles 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/evandrojr/opensubtitles.png)](http://travis-ci.org/evandrojr/opensubtitles)
7
+
8
+ ## Examples
9
+
10
+ Just read the source of `bin/getsub` it is a typical example of Opensubtitles's capacities.
11
+
12
+ ## getsub
13
+
14
+ The opensubtitles gem provide a simple script to find and download the best subtitle on
15
+ [opensubtitles.org](http://www.opensubtitles.org/) for your video file.
16
+
17
+ ### Installation
18
+
19
+ $ gem install opensubtitles
20
+
21
+ ### Usage
22
+
23
+ getsub [options] DIRECTORY | VIDEO_FILE [VIDEO_FILE ...]
24
+
25
+ You just have to execute `getsub` with some video files in arguments:
26
+
27
+ $ getsub somemovie.avi othermovie.mkv
28
+
29
+ Or specify a directory to search recursively:
30
+
31
+ $ getsub ~/Movies
32
+
33
+ For options details just run:
34
+
35
+ $ getsub --help
36
+
37
+ Main options:
38
+
39
+ -a, --auto Do not ask user to resolve hash conflicts.
40
+
41
+ -l, --language LANGUAGE Sub language ISO 639-2 code like fre or eng. Default: env $LANG (your-lang)
42
+
43
+ -f, --force Download sub even if video already has one
44
+
45
+ -t, --type FORMATS Select only subtitles in specified formats. e.g -t srt,sub
46
+
47
+ -L, --language-extension Add the ISO 639-2 in the subtitle's file extension. e.g filename.eng.srt
48
+
49
+ -s, --search-by METHODS Ordered list of search methods. h: by movie hash, i: by name on IMDB, n: by name on Opensubtitles, p: by filename on Opensubtitles. e.g -s hi . Default: h
50
+
@@ -0,0 +1,9 @@
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
@@ -0,0 +1,157 @@
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', 'opensubtitles'))
6
+
7
+
8
+ class GetSub
9
+
10
+ def initialize
11
+ @options = {:language => Opensubtitles.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 (#{Opensubtitles.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 Opensubtitles, p: by filename on Opensubtitles. 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| Opensubtitles::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("**/*.{#{Opensubtitles::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/opensubtitles/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 ||= Opensubtitles::SubtitleFinder.new(search_engines, finders, selectors)
100
+ end
101
+
102
+ SEARCH_ENGINES = {
103
+ 'h' => Opensubtitles::Search::MovieHash,
104
+ 'i' => Opensubtitles::Search::IMDB,
105
+ 'n' => Opensubtitles::Search::Name,
106
+ 'p' => Opensubtitles::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
+ [Opensubtitles::Finder::Score.new]
117
+ end
118
+
119
+ def selectors
120
+ movie_finder = if @options[:auto]
121
+ Opensubtitles::Finder::First.new # TODO: try to match subtitle movie name with filename
122
+ else
123
+ Opensubtitles::Finder::Interactive.new
124
+ end
125
+
126
+ selectors = [
127
+ Opensubtitles::Selector::Movie.new(movie_finder)
128
+ ]
129
+ selectors << Opensubtitles::Selector::Format.new(@options[:formats]) if @options[:formats]
130
+ selectors
131
+ end
132
+
133
+ def server
134
+ @server ||= Opensubtitles::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)
@@ -0,0 +1,21 @@
1
+ require 'xmlrpc/client'
2
+
3
+ module Opensubtitles
4
+ base_path = File.expand_path(File.dirname(__FILE__) + '/opensubtitles')
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
+ Opensubtitles::Language.from_locale(ENV['LANG'] || 'en_US.UTF-8')
19
+ end
20
+
21
+ end
@@ -0,0 +1,8 @@
1
+ module Opensubtitles
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
@@ -0,0 +1,13 @@
1
+ module Opensubtitles
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
@@ -0,0 +1,21 @@
1
+ module Opensubtitles
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
@@ -0,0 +1,13 @@
1
+ module Opensubtitles
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
@@ -0,0 +1,84 @@
1
+ module Opensubtitles
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
@@ -0,0 +1,16 @@
1
+ module Opensubtitles
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