tmdb_party 0.4.1 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +3 -1
- data/Rakefile +9 -20
- data/VERSION.yml +2 -2
- data/lib/tmdb_party.rb +32 -18
- data/lib/tmdb_party/attributes.rb +29 -13
- data/lib/tmdb_party/cast_member.rb +36 -0
- data/lib/tmdb_party/country.rb +25 -0
- data/lib/tmdb_party/image.rb +39 -14
- data/lib/tmdb_party/movie.rb +28 -31
- data/lib/tmdb_party/person.rb +19 -11
- data/lib/tmdb_party/studio.rb +19 -0
- data/{test → spec}/fixtures/imdb_no_results.json +0 -0
- data/{test → spec}/fixtures/imdb_search.json +0 -0
- data/spec/fixtures/megan_fox.json +630 -0
- data/{test → spec}/fixtures/no_groups.json +0 -0
- data/spec/fixtures/nothing_found.json +1 -0
- data/{test → spec}/fixtures/rad.json +0 -0
- data/{test → spec}/fixtures/search.json +0 -0
- data/spec/fixtures/search_person.json +38 -0
- data/spec/fixtures/shitty_shit_result.json +1 -0
- data/{test → spec}/fixtures/single_result.json +0 -0
- data/{test → spec}/fixtures/transformers.json +16 -3
- data/spec/lib/tmdb_party/cast_member_spec.rb +52 -0
- data/spec/lib/tmdb_party/country_spec.rb +24 -0
- data/spec/lib/tmdb_party/image_spec.rb +73 -0
- data/spec/lib/tmdb_party/movie_spec.rb +110 -0
- data/spec/lib/tmdb_party/person_spec.rb +55 -0
- data/spec/lib/tmdb_party/studio_spec.rb +20 -0
- data/spec/lib/tmdb_party_spec.rb +103 -0
- data/{test/test_helper.rb → spec/spec_helper.rb} +1 -9
- data/tmdb_party.gemspec +35 -14
- metadata +33 -12
data/README.rdoc
CHANGED
@@ -4,6 +4,7 @@ Simple ruby wrapper to themoviedb.org (http://api.themoviedb.org/2.0/docs/) usin
|
|
4
4
|
|
5
5
|
= usage:
|
6
6
|
sudo gem install tmdb_party -s http://gemcutter.org
|
7
|
+
require 'rubygems'
|
7
8
|
require 'tmdb_party'
|
8
9
|
|
9
10
|
= example:
|
@@ -14,7 +15,7 @@ Simple ruby wrapper to themoviedb.org (http://api.themoviedb.org/2.0/docs/) usin
|
|
14
15
|
results.length
|
15
16
|
# => 5
|
16
17
|
|
17
|
-
transformers = results.detect{|m| m.
|
18
|
+
transformers = results.detect{|m| m.name == "Transformers"}
|
18
19
|
|
19
20
|
transformers.popularity
|
20
21
|
# => 31
|
@@ -37,6 +38,7 @@ It's a movie database, kind of like IMDB except it's more of a community wiki. T
|
|
37
38
|
|
38
39
|
== Contributors
|
39
40
|
Jon Maddox (http://github.com/maddox)
|
41
|
+
Magnus Bergmark (http://github.com/Mange)
|
40
42
|
|
41
43
|
== Copyright
|
42
44
|
|
data/Rakefile
CHANGED
@@ -12,7 +12,7 @@ begin
|
|
12
12
|
gem.add_dependency('httparty', '>= 0.4.3')
|
13
13
|
|
14
14
|
gem.add_development_dependency('fakeweb')
|
15
|
-
gem.add_development_dependency('
|
15
|
+
gem.add_development_dependency('rspec')
|
16
16
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
17
17
|
end
|
18
18
|
Jeweler::GemcutterTasks.new
|
@@ -20,28 +20,18 @@ rescue LoadError
|
|
20
20
|
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
21
21
|
end
|
22
22
|
|
23
|
-
require 'rake/
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
test.verbose = true
|
23
|
+
require 'spec/rake/spectask'
|
24
|
+
desc "Run all examples"
|
25
|
+
Spec::Rake::SpecTask.new('spec') do |t|
|
26
|
+
t.pattern = 'spec/**/*_spec.rb'
|
28
27
|
end
|
29
28
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
test.libs << 'test'
|
34
|
-
test.pattern = 'test/**/*_test.rb'
|
35
|
-
test.verbose = true
|
36
|
-
end
|
37
|
-
rescue LoadError
|
38
|
-
task :rcov do
|
39
|
-
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
40
|
-
end
|
29
|
+
Spec::Rake::SpecTask.new('rcov') do |t|
|
30
|
+
t.pattern = 'spec/**/*_spec.rb'
|
31
|
+
t.rcov = true
|
41
32
|
end
|
42
33
|
|
43
|
-
|
44
|
-
task :default => :test
|
34
|
+
task :default => :spec
|
45
35
|
|
46
36
|
require 'rake/rdoctask'
|
47
37
|
Rake::RDocTask.new do |rdoc|
|
@@ -57,4 +47,3 @@ Rake::RDocTask.new do |rdoc|
|
|
57
47
|
rdoc.rdoc_files.include('README*')
|
58
48
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
59
49
|
end
|
60
|
-
|
data/VERSION.yml
CHANGED
data/lib/tmdb_party.rb
CHANGED
@@ -1,13 +1,9 @@
|
|
1
1
|
# gem 'httparty'
|
2
2
|
require 'httparty'
|
3
|
-
|
4
|
-
|
5
|
-
require
|
6
|
-
|
7
|
-
require 'tmdb_party/genre'
|
8
|
-
require 'tmdb_party/person'
|
9
|
-
require 'tmdb_party/image'
|
10
|
-
require 'tmdb_party/movie'
|
3
|
+
|
4
|
+
%w[core_extensions httparty_icebox attributes video genre person image country studio cast_member movie].each do |class_name|
|
5
|
+
require "tmdb_party/#{class_name}"
|
6
|
+
end
|
11
7
|
|
12
8
|
module TMDBParty
|
13
9
|
class Base
|
@@ -18,18 +14,13 @@ module TMDBParty
|
|
18
14
|
base_uri 'http://api.themoviedb.org/2.1'
|
19
15
|
format :json
|
20
16
|
|
21
|
-
def initialize(key)
|
17
|
+
def initialize(key, lang = 'en')
|
22
18
|
@api_key = key
|
23
|
-
|
24
|
-
|
25
|
-
def default_path_items
|
26
|
-
path_items = ['en']
|
27
|
-
path_items << 'json'
|
28
|
-
path_items << @api_key
|
19
|
+
@lang = lang
|
29
20
|
end
|
30
21
|
|
31
22
|
def search(query)
|
32
|
-
data = self.class.get(
|
23
|
+
data = self.class.get(method_url('Movie.search', query))
|
33
24
|
if data.class != Array || data.first == "Nothing found."
|
34
25
|
[]
|
35
26
|
else
|
@@ -37,8 +28,17 @@ module TMDBParty
|
|
37
28
|
end
|
38
29
|
end
|
39
30
|
|
31
|
+
def search_person(query)
|
32
|
+
data = self.class.get(method_url('Person.search', query))
|
33
|
+
if data.class != Array || data.first == "Nothing found."
|
34
|
+
[]
|
35
|
+
else
|
36
|
+
data.collect { |person| Person.new(person, self) }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
40
|
def imdb_lookup(imdb_id)
|
41
|
-
data = self.class.get(
|
41
|
+
data = self.class.get(method_url('Movie.imdbLookup', imdb_id))
|
42
42
|
if data.class != Array || data.first == "Nothing found."
|
43
43
|
nil
|
44
44
|
else
|
@@ -47,8 +47,22 @@ module TMDBParty
|
|
47
47
|
end
|
48
48
|
|
49
49
|
def get_info(id)
|
50
|
-
data = self.class.get(
|
50
|
+
data = self.class.get(method_url('Movie.getInfo', id))
|
51
51
|
Movie.new(data.first, self)
|
52
52
|
end
|
53
|
+
|
54
|
+
def get_person(id)
|
55
|
+
data = self.class.get(method_url('Person.getInfo', id))
|
56
|
+
Person.new(data.first, self)
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
def default_path_items
|
61
|
+
[@lang, 'json', @api_key]
|
62
|
+
end
|
63
|
+
|
64
|
+
def method_url(method, value)
|
65
|
+
'/' + ([method] + default_path_items + [URI.escape(value.to_s)]).join('/')
|
66
|
+
end
|
53
67
|
end
|
54
68
|
end
|
@@ -20,15 +20,14 @@ module TMDBParty
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def attribute(name, options)
|
23
|
-
options
|
24
|
-
raise "Name can't be empty" if name.blank?
|
25
|
-
|
26
|
-
class_eval <<-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
EOS
|
23
|
+
options = {:type => 'nil', :lazy => false}.merge(options)
|
24
|
+
raise ArgumentError, "Name can't be empty" if name.blank?
|
25
|
+
|
26
|
+
class_eval <<-EVAL
|
27
|
+
def #{name}
|
28
|
+
read_or_load_attribute('#{name}', #{options[:type]}, #{options[:lazy].inspect})
|
29
|
+
end
|
30
|
+
EVAL
|
32
31
|
end
|
33
32
|
|
34
33
|
end
|
@@ -43,10 +42,27 @@ module TMDBParty
|
|
43
42
|
end
|
44
43
|
|
45
44
|
private
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
45
|
+
def read_or_load_attribute(name, type, lazy_method)
|
46
|
+
if lazy_method.is_a?(Symbol) and raw_attribute_missing?(name) and not loaded?
|
47
|
+
self.send(lazy_method)
|
48
|
+
end
|
49
|
+
read_attribute(name, type)
|
50
|
+
end
|
51
|
+
|
52
|
+
def read_attribute(name, type = nil)
|
53
|
+
@attributes_cache ||= {}
|
54
|
+
@attributes_cache[name] ||= decode_raw_attribute(@attributes[name], type) if @attributes
|
55
|
+
end
|
56
|
+
|
57
|
+
def raw_attribute_missing?(name)
|
58
|
+
not @attributes.has_key?(name.to_s)
|
59
|
+
end
|
60
|
+
|
61
|
+
def decode_raw_attribute(value, type)
|
62
|
+
return nil unless value
|
63
|
+
type.respond_to?(:parse) ? type.parse(value) : value
|
64
|
+
end
|
65
|
+
|
50
66
|
end
|
51
67
|
end
|
52
68
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module TMDBParty
|
2
|
+
class CastMember
|
3
|
+
include Attributes
|
4
|
+
attr_reader :tmdb
|
5
|
+
attributes :name, :url, :job, :department
|
6
|
+
attributes :id, :type => Integer
|
7
|
+
|
8
|
+
def initialize(values, tmdb)
|
9
|
+
@tmdb = tmdb
|
10
|
+
self.attributes = values
|
11
|
+
end
|
12
|
+
|
13
|
+
def character_name
|
14
|
+
read_attribute('character')
|
15
|
+
end
|
16
|
+
|
17
|
+
def image_url
|
18
|
+
read_attribute('profile')
|
19
|
+
end
|
20
|
+
|
21
|
+
def person
|
22
|
+
tmdb.get_person(id)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.parse(data, tmdb)
|
26
|
+
return unless data
|
27
|
+
if data.is_a?(Array)
|
28
|
+
data.collect do |person|
|
29
|
+
CastMember.new(person, tmdb)
|
30
|
+
end
|
31
|
+
else
|
32
|
+
[CastMember.new(data, tmdb)]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module TMDBParty
|
2
|
+
class Country
|
3
|
+
include Attributes
|
4
|
+
attributes :name, :code, :url
|
5
|
+
alias_method :code_string, :code
|
6
|
+
|
7
|
+
def self.parse(data)
|
8
|
+
return unless data
|
9
|
+
if data.is_a?(Array)
|
10
|
+
data.map { |row| Country.new(row) }
|
11
|
+
else
|
12
|
+
[Country.new(data)]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(attributes)
|
17
|
+
self.attributes = attributes
|
18
|
+
end
|
19
|
+
|
20
|
+
def code
|
21
|
+
code_string.downcase.to_sym
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
data/lib/tmdb_party/image.rb
CHANGED
@@ -1,24 +1,49 @@
|
|
1
1
|
module TMDBParty
|
2
2
|
class Image
|
3
|
-
|
3
|
+
def initialize(attributes)
|
4
|
+
@attributes = attributes
|
5
|
+
end
|
4
6
|
|
5
|
-
def
|
6
|
-
@
|
7
|
-
@type = options["type"]
|
8
|
-
@size = options["size"]
|
7
|
+
def id
|
8
|
+
@attributes['id']
|
9
9
|
end
|
10
10
|
|
11
|
-
def
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
11
|
+
def type
|
12
|
+
@attributes['type'].downcase.to_sym
|
13
|
+
end
|
14
|
+
|
15
|
+
def sizes
|
16
|
+
@attributes['sizes'].map { |size| size.downcase.to_sym }.to_set
|
17
|
+
end
|
18
|
+
|
19
|
+
def url
|
20
|
+
original_url
|
21
|
+
end
|
22
|
+
|
23
|
+
def method_missing(*args, &block)
|
24
|
+
if args.first.to_s =~ /\A(.*)_url\Z/
|
25
|
+
@attributes["#{$1}_url"]
|
19
26
|
else
|
20
|
-
|
27
|
+
super
|
21
28
|
end
|
22
29
|
end
|
30
|
+
|
31
|
+
class << self
|
32
|
+
def parse(data)
|
33
|
+
data.map { |row| row['image'] }.group_by { |row| row['id'] }.map do |id, images|
|
34
|
+
Image.new(reduce_images(images))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
protected
|
39
|
+
def reduce_images(images)
|
40
|
+
images.inject({'sizes' => []}) do |image, row|
|
41
|
+
image["#{row['size']}_url"] = row.delete('url')
|
42
|
+
image['sizes'] << row.delete('size')
|
43
|
+
image.merge(row)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
23
48
|
end
|
24
49
|
end
|
data/lib/tmdb_party/movie.rb
CHANGED
@@ -3,20 +3,21 @@ module TMDBParty
|
|
3
3
|
include Attributes
|
4
4
|
attr_reader :tmdb
|
5
5
|
|
6
|
-
attributes :name, :overview, :id, :
|
6
|
+
attributes :name, :overview, :id, :imdb_id, :movie_type, :url, :alternative_title, :translated, :certification
|
7
7
|
attributes :released
|
8
|
-
attributes :id, :type => Integer
|
9
|
-
attributes :
|
8
|
+
attributes :id, :popularity, :type => Integer
|
9
|
+
attributes :score, :type => Float
|
10
10
|
|
11
|
-
attributes :
|
11
|
+
attributes :tagline, :lazy => :get_info!
|
12
|
+
attributes :posters, :backdrops, :lazy => :get_info!, :type => Image
|
12
13
|
attributes :homepage, :lazy => :get_info!
|
13
14
|
attributes :trailer, :lazy => :get_info!
|
14
15
|
attributes :runtime, :lazy => :get_info!, :type => Integer
|
15
16
|
attributes :genres, :lazy => :get_info!, :type => Genre
|
16
|
-
attributes :
|
17
|
+
attributes :countries, :lazy => :get_info!, :type => Country
|
18
|
+
attributes :studios, :lazy => :get_info!, :type => Studio
|
17
19
|
|
18
|
-
alias_method :
|
19
|
-
alias_method :flattened_backdrops, :backdrops
|
20
|
+
alias_method :translated?, :translated
|
20
21
|
|
21
22
|
def initialize(values, tmdb)
|
22
23
|
@tmdb = tmdb
|
@@ -29,45 +30,41 @@ module TMDBParty
|
|
29
30
|
@loaded = true
|
30
31
|
end
|
31
32
|
|
33
|
+
def cast
|
34
|
+
# TODO: This needs refactoring
|
35
|
+
CastMember.parse(read_or_load_attribute('cast', nil, :get_info!), tmdb)
|
36
|
+
end
|
37
|
+
|
38
|
+
def language
|
39
|
+
read_attribute('language').downcase.to_sym
|
40
|
+
end
|
41
|
+
|
42
|
+
def last_modified_at
|
43
|
+
# Date from TMDB is always in MST, but no timezone is present in date string
|
44
|
+
Time.parse(read_attribute('last_modified_at') + ' MST')
|
45
|
+
end
|
46
|
+
|
32
47
|
def directors
|
33
|
-
find_cast('
|
48
|
+
find_cast('Directing')
|
34
49
|
end
|
35
50
|
|
36
51
|
def actors
|
37
|
-
find_cast('
|
52
|
+
find_cast('Actors')
|
38
53
|
end
|
39
54
|
|
40
55
|
def writers
|
41
|
-
find_cast('
|
42
|
-
end
|
43
|
-
|
44
|
-
def posters
|
45
|
-
process_art(flattened_posters)
|
56
|
+
find_cast('Writing')
|
46
57
|
end
|
47
58
|
|
48
|
-
def
|
49
|
-
|
59
|
+
def producers
|
60
|
+
find_cast('Production')
|
50
61
|
end
|
51
62
|
|
52
|
-
|
53
63
|
private
|
54
64
|
|
55
|
-
def process_art(art)
|
56
|
-
image_groups = {}
|
57
|
-
art.each do |image_hash|
|
58
|
-
the_image = image_hash["image"]
|
59
|
-
if image_groups[the_image["id"]]
|
60
|
-
image_groups[the_image["id"]][the_image["size"]] = the_image["url"]
|
61
|
-
else
|
62
|
-
image_groups[the_image["id"]] = {the_image["size"] => the_image["url"]}
|
63
|
-
end
|
64
|
-
end
|
65
|
-
image_groups.values
|
66
|
-
end
|
67
|
-
|
68
65
|
def find_cast(type)
|
69
66
|
return [] unless cast
|
70
|
-
guys = cast.select{|c| c.
|
67
|
+
guys = cast.select{|c| c.department == type}
|
71
68
|
end
|
72
69
|
|
73
70
|
end
|
data/lib/tmdb_party/person.rb
CHANGED
@@ -1,21 +1,29 @@
|
|
1
1
|
module TMDBParty
|
2
2
|
class Person
|
3
3
|
include Attributes
|
4
|
-
|
4
|
+
attr_reader :tmdb
|
5
|
+
attributes :id, :popularity, :type => Integer
|
6
|
+
attributes :score, :type => Float
|
7
|
+
attributes :name, :url, :biography
|
5
8
|
|
6
|
-
|
9
|
+
attributes :birthplace, :birthday, :lazy => :get_info!
|
10
|
+
|
11
|
+
def initialize(values, tmdb)
|
12
|
+
@tmdb = tmdb
|
7
13
|
self.attributes = values
|
8
14
|
end
|
9
15
|
|
10
|
-
def
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
def biography
|
17
|
+
# HTTParty does not parse the encoded hexadecimal properly. It does not consider 000F to be a hex, but 000f is
|
18
|
+
# A bug has been submitted about this
|
19
|
+
read_attribute('biography').gsub("\\n", "\n").gsub(/\\u([0-9A-F]{4})/) { [$1.hex].pack("U") }
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
def get_info!
|
24
|
+
person = tmdb.get_person(self.id)
|
25
|
+
@attributes.merge!(person.attributes) if person
|
26
|
+
@loaded = true
|
19
27
|
end
|
20
28
|
end
|
21
29
|
end
|