unified_db 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'rake'
data/README.md ADDED
@@ -0,0 +1,5 @@
1
+ # Unified Movie Database
2
+
3
+ This is project for unifying multiple movie database. Currently it support only IMDB and TVDB, but TMDB will be done shortly.
4
+
5
+ To see it in action please go to [demo site](http://unified-db.heroku.com)
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new do |t|
7
+ t.rspec_opts = ["-c", "-f progress"]
8
+ t.pattern = 'spec/**/*_spec.rb'
9
+ end
10
+
11
+ task :default => :spec
data/lib/ext/crack.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'crack/json'
2
+ require 'yajl'
3
+
4
+ module Crack
5
+ class JSON
6
+ def self.parse(json)
7
+ Yajl::Parser.parse(json)
8
+ end
9
+ end
10
+ end
data/lib/unified_db.rb ADDED
@@ -0,0 +1,19 @@
1
+ module UnifiedDB
2
+
3
+ ROOT = File.expand_path(File.dirname(__FILE__))
4
+
5
+ autoload :ApiError, "#{ROOT}/unified_db/api_error"
6
+ autoload :Backend, "#{ROOT}/unified_db/backend"
7
+ autoload :Result, "#{ROOT}/unified_db/result"
8
+ autoload :Version, "#{ROOT}/unified_db/version"
9
+
10
+ class << self
11
+ attr_accessor :json_encoder, :tvdb_secret
12
+
13
+ def json_encoder
14
+ @json_encoder ||= Yajl::Encoder.new
15
+ end
16
+ end
17
+ end
18
+
19
+ require "#{UnifiedDB::ROOT}/ext/crack"
@@ -0,0 +1,16 @@
1
+ module UnifiedDB
2
+ class ApiError < RuntimeError
3
+
4
+ def to_h
5
+ {
6
+ :result => 'error',
7
+ :reason => message
8
+ }
9
+ end
10
+
11
+ def to_json(*args)
12
+ UnifiedDB.json_encoder.encode to_h
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,18 @@
1
+ module UnifiedDB
2
+ module Backend
3
+
4
+ autoload :Base, "#{ROOT}/unified_db/backend/base"
5
+ autoload :IMDB, "#{ROOT}/unified_db/backend/imdb"
6
+ autoload :TVDB, "#{ROOT}/unified_db/backend/tvdb"
7
+
8
+ AVAILABLE = {
9
+ 'imdb' => Backend::IMDB,
10
+ 'tvdb' => Backend::TVDB
11
+ }
12
+
13
+ def self.select(name)
14
+ AVAILABLE[name.to_s]
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,66 @@
1
+ module UnifiedDB
2
+ module Backend
3
+ class Base
4
+
5
+ attr_accessor :id, :title
6
+
7
+ def self.find(params)
8
+ new.find(params)
9
+ end
10
+
11
+ def initialize
12
+ @result = []
13
+ end
14
+
15
+ def find(params)
16
+ if params[:id]
17
+ find_by_id params[:id]
18
+ elsif params[:t] || params[:title]
19
+ find_by_title(params[:t] || params[:title])
20
+ else
21
+ raise ApiError, 'no search criteria specified'
22
+ end
23
+
24
+ result
25
+ rescue ApiError => e
26
+ {
27
+ :status => 'error',
28
+ :reason => e.message
29
+ }
30
+ end
31
+
32
+ def find_by_id(id)
33
+ raise ApiError, 'not implemented'
34
+ end
35
+
36
+ def find_by_title(title)
37
+ raise ApiError, 'not implemented'
38
+ end
39
+
40
+ def result
41
+ {
42
+ :status => 'success',
43
+ :service => service,
44
+ :result => @result
45
+ }
46
+ end
47
+
48
+ private
49
+
50
+ def service; 'base'; end
51
+
52
+ def format_actors(actors)
53
+ Array(actors).collect { |a| { a.name => a.role } }
54
+ end
55
+
56
+ def format_directors(directors)
57
+ Array(directors).collect(&:name)
58
+ end
59
+
60
+ def format_writers(writers)
61
+ Array(writers).collect(&:name)
62
+ end
63
+
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,46 @@
1
+ require 'imdb_party'
2
+
3
+ module UnifiedDB
4
+ module Backend
5
+ class IMDB < Base
6
+
7
+ def find_by_id(id)
8
+ movie = handler.find_movie_by_id(id)
9
+ @result = Result::ID.new(
10
+ :id => movie.imdb_id,
11
+ :title => movie.title,
12
+ :overview => movie.plot,
13
+ :release_date => movie.release_date,
14
+ :genres => movie.genres,
15
+ :rating => movie.rating,
16
+ :runtime => movie.runtime.to_i,
17
+ :actors => format_actors(movie.actors),
18
+ :directors => format_directors(movie.directors),
19
+ :writers => format_writers(movie.writers),
20
+ :posters => Array(movie.poster_url)
21
+ )
22
+ rescue
23
+ raise ApiError, 'not found'
24
+ end
25
+
26
+ def find_by_title(title)
27
+ movies = handler.find_by_title(title)
28
+ movies.each do |movie|
29
+ @result << Result::Title.new(
30
+ :id => movie[:imdb_id],
31
+ :title => movie[:title],
32
+ :year => movie[:year])
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def service; 'imdb'; end
39
+
40
+ def handler
41
+ @handler ||= ImdbParty::Imdb.new(:anonymize => true)
42
+ end
43
+
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,51 @@
1
+ require 'tvdb_party'
2
+
3
+ module UnifiedDB
4
+ module Backend
5
+ class TVDB < Base
6
+
7
+ def find_by_id(id)
8
+ movie = handler.get_series_by_id(id)
9
+ @result = Result::ID.new(
10
+ :id => movie.id,
11
+ :title => movie.name,
12
+ :overview => movie.overview,
13
+ :release_date => movie.first_aired.to_s,
14
+ :genres => movie.genres,
15
+ :rating => movie.rating,
16
+ :runtime => movie.runtime.to_i,
17
+ :actors => format_actors(movie.actors),
18
+ :directors => [],
19
+ :writers => [],
20
+ :posters => format_posters(movie.banners)
21
+ )
22
+ rescue
23
+ raise ApiError, 'not found'
24
+ end
25
+
26
+ def find_by_title(title)
27
+ movies = handler.search(title)
28
+ movies.each do |movie|
29
+ @result << Result::Title.new(
30
+ :id => movie['seriesid'],
31
+ :title => movie['SeriesName'],
32
+ :year => movie['FirstAired'].to_s.split('-')[0])
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def service; 'tvdb'; end
39
+
40
+ def handler
41
+ raise ApiError, 'no TVDB secret provided' if UnifiedDB.tvdb_secret.nil?
42
+ @handler ||= TvdbParty::Search.new(UnifiedDB.tvdb_secret)
43
+ end
44
+
45
+ def format_posters(posters)
46
+ posters.select{|poster| poster.banner_type == 'season'}.collect(&:url)
47
+ end
48
+
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,9 @@
1
+ module UnifiedDB
2
+ module Result
3
+
4
+ autoload :Base, "#{ROOT}/unified_db/result/base"
5
+ autoload :ID, "#{ROOT}/unified_db/result/id"
6
+ autoload :Title, "#{ROOT}/unified_db/result/title"
7
+
8
+ end
9
+ end
@@ -0,0 +1,29 @@
1
+ module UnifiedDB
2
+ module Result
3
+ class Base
4
+
5
+ def self.allowed_keys; []; end
6
+
7
+ def initialize(params)
8
+ allowed_keys.each do |key|
9
+ instance_variable_set("@#{key}", params[key])
10
+ end
11
+ end
12
+
13
+ def to_h
14
+ allowed_keys.inject({}) { |hash, key| hash[key] = instance_variable_get("@#{key}"); hash }
15
+ end
16
+
17
+ def to_json(*args)
18
+ UnifiedDB.json_encoder.encode to_h
19
+ end
20
+
21
+ private
22
+
23
+ def allowed_keys
24
+ self.class.allowed_keys
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,13 @@
1
+ module UnifiedDB
2
+ module Result
3
+ class ID < Base
4
+
5
+ def self.allowed_keys
6
+ [ :id, :title, :overview, :release_date, :genres, :rating, :runtime, :actors, :directors, :writers, :posters ]
7
+ end
8
+
9
+ attr_reader *allowed_keys
10
+
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module UnifiedDB
2
+ module Result
3
+ class Title < Base
4
+
5
+ def self.allowed_keys
6
+ [ :id, :title, :year ]
7
+ end
8
+
9
+ attr_reader *allowed_keys
10
+
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ module UnifiedDB
2
+
3
+ VERSION = '0.1.0'
4
+
5
+ end
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'rspec'
3
+ require 'yajl'
4
+
5
+ require 'unified_db'
6
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
7
+
8
+ # This is secret is for testing purposes
9
+ # PLEASE don't copy and reuse it :)
10
+ UnifiedDB.tvdb_secret = '7ED5C5E4CAFAF90E'
@@ -0,0 +1,83 @@
1
+ require 'spec_helper'
2
+
3
+ describe UnifiedDB::Backend::IMDB do
4
+ subject { described_class.new }
5
+
6
+ it "should return valid find by title" do
7
+ result = subject.find(:title => 'Dark Knight')
8
+ result.class.should eql(Hash)
9
+ result.keys.sort.should eql([:result, :service, :status])
10
+ result[:status].should eql('success')
11
+ result[:service].should eql('imdb')
12
+ result[:result].class.should eql(Array)
13
+ result[:result].size.should be > 18
14
+
15
+ first_result = result[:result].first
16
+ first_result.class.should eql(UnifiedDB::Result::Title)
17
+ first_result.id.should eql('tt0468569')
18
+ first_result.title.should eql('The Dark Knight')
19
+ first_result.year.should eql('2008')
20
+
21
+ encoded = Yajl::Encoder.new.encode result
22
+ decoded = Yajl::Parser.new.parse encoded
23
+
24
+ decoded.class.should eql(Hash)
25
+ decoded.keys.sort.should eql(['result', 'service', 'status'])
26
+ decoded['status'].should eql('success')
27
+ decoded['service'].should eql('imdb')
28
+ decoded['result'].class.should eql(Array)
29
+ decoded['result'].size.should be > 18
30
+
31
+ first_result = decoded['result'].first
32
+ first_result.class.should eql(Hash)
33
+ first_result['id'].should eql('tt0468569')
34
+ first_result['title'].should eql('The Dark Knight')
35
+ first_result['year'].should eql('2008')
36
+ end
37
+
38
+ it "should return empty array if invalid find by title specified" do
39
+ result = subject.find(:title => "qwertyuiopasdfghjkllzxcvbnm")
40
+ result.class.should eql(Hash)
41
+ result.keys.sort.should eql([:result, :service, :status])
42
+ result[:status].should eql('success')
43
+ result[:service].should eql('imdb')
44
+ result[:result].class.should eql(Array)
45
+ result[:result].size.should eql(0)
46
+ end
47
+
48
+
49
+ it "should return valid find by id" do
50
+ result = subject.find(:id => 'tt0468569')
51
+ result.class.should eql(Hash)
52
+ result.keys.sort.should eql([:result, :service, :status])
53
+ result[:status].should eql('success')
54
+ result[:service].should eql('imdb')
55
+
56
+ result[:result].class.should eql(UnifiedDB::Result::ID)
57
+ result[:result].id.should eql('tt0468569')
58
+ result[:result].title.should eql('The Dark Knight')
59
+ result[:result].overview.class.should eql(String)
60
+ result[:result].overview.length.should be > 20
61
+ result[:result].release_date.class.should eql(String)
62
+ result[:result].genres.should eql(["Action", "Crime", "Thriller"])
63
+ result[:result].rating.class.should eql(Float)
64
+ result[:result].rating.should be > 4
65
+ result[:result].rating.should be < 10
66
+ result[:result].runtime.should eql(152)
67
+ result[:result].actors.class.should eql(Array)
68
+ result[:result].actors.first.should eql({"Christian Bale" => "Bruce Wayne/Batman"})
69
+ result[:result].directors.should eql(["Christopher Nolan"])
70
+ result[:result].writers.should eql(["Jonathan Nolan", "Christopher Nolan"])
71
+ result[:result].posters.class.should eql(Array)
72
+ result[:result].posters.size.should be > 0
73
+ end
74
+
75
+ it "should return error if id was not found" do
76
+ result = subject.find(:id => 'tt046856910')
77
+ result.class.should eql(Hash)
78
+ result.keys.sort.should eql([:reason, :status])
79
+ result[:status].should eql('error')
80
+ result[:reason].should eql('not found')
81
+ end
82
+
83
+ end
@@ -0,0 +1,83 @@
1
+ require 'spec_helper'
2
+
3
+ describe UnifiedDB::Backend::TVDB do
4
+ subject { described_class.new }
5
+
6
+ it "should return valid find by title" do
7
+ result = subject.find(:title => 'StarGate')
8
+ result.class.should eql(Hash)
9
+ result.keys.sort.should eql([:result, :service, :status])
10
+ result[:status].should eql('success')
11
+ result[:service].should eql('tvdb')
12
+ result[:result].class.should eql(Array)
13
+ result[:result].size.should be > 3
14
+
15
+ first_result = result[:result].first
16
+ first_result.class.should eql(UnifiedDB::Result::Title)
17
+ first_result.id.should eql('72449')
18
+ first_result.title.should eql('Stargate SG-1')
19
+ first_result.year.should eql('1997')
20
+
21
+ encoded = Yajl::Encoder.new.encode result
22
+ decoded = Yajl::Parser.new.parse encoded
23
+
24
+ decoded.class.should eql(Hash)
25
+ decoded.keys.sort.should eql(['result', 'service', 'status'])
26
+ decoded['status'].should eql('success')
27
+ decoded['service'].should eql('tvdb')
28
+ decoded['result'].class.should eql(Array)
29
+ decoded['result'].size.should be > 3
30
+
31
+ first_result = decoded['result'].first
32
+ first_result.class.should eql(Hash)
33
+ first_result['id'].should eql('72449')
34
+ first_result['title'].should eql('Stargate SG-1')
35
+ first_result['year'].should eql('1997')
36
+ end
37
+
38
+ it "should return empty array if invalid find by title specified" do
39
+ result = subject.find(:title => "qwertyuiopasdfghjkllzxcvbnm")
40
+ result.class.should eql(Hash)
41
+ result.keys.sort.should eql([:result, :service, :status])
42
+ result[:status].should eql('success')
43
+ result[:service].should eql('tvdb')
44
+ result[:result].class.should eql(Array)
45
+ result[:result].size.should eql(0)
46
+ end
47
+
48
+
49
+ it "should return valid find by id" do
50
+ result = subject.find(:id => '72449')
51
+ result.class.should eql(Hash)
52
+ result.keys.sort.should eql([:result, :service, :status])
53
+ result[:status].should eql('success')
54
+ result[:service].should eql('tvdb')
55
+
56
+ result[:result].class.should eql(UnifiedDB::Result::ID)
57
+ result[:result].id.should eql('72449')
58
+ result[:result].title.should eql('Stargate SG-1')
59
+ result[:result].overview.class.should eql(String)
60
+ result[:result].overview.length.should be > 20
61
+ result[:result].release_date.class.should eql(String)
62
+ result[:result].genres.should eql(["Action and Adventure", "Science-Fiction"])
63
+ result[:result].rating.class.should eql(Float)
64
+ result[:result].rating.should be > 4
65
+ result[:result].rating.should be < 10
66
+ result[:result].runtime.should eql(60)
67
+ result[:result].actors.class.should eql(Array)
68
+ result[:result].actors.first.should eql({"Richard Dean Anderson"=>"Col./Gen. Jack O'Neill"})
69
+ result[:result].directors.should eql([])
70
+ result[:result].writers.should eql([])
71
+ result[:result].posters.class.should eql(Array)
72
+ result[:result].posters.size.should be > 0
73
+ end
74
+
75
+ it "should return error if id was not found" do
76
+ result = subject.find(:id => '72449123')
77
+ result.class.should eql(Hash)
78
+ result.keys.sort.should eql([:reason, :status])
79
+ result[:status].should eql('error')
80
+ result[:reason].should eql('not found')
81
+ end
82
+
83
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "unified_db/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "unified_db"
7
+ s.version = UnifiedDB::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Bernard Potocki"]
10
+ s.email = ["bernard.potocki@imanel.org"]
11
+ s.homepage = "http://github.com/imanel/unifieddb"
12
+ s.summary = %q{Scrapper for multiple Movie Databases}
13
+ s.description = %q{Scrapper for multiple Movie Databases}
14
+
15
+ s.add_dependency 'yajl-ruby'
16
+ s.add_dependency 'imdb_party', '~> 0.6.0'
17
+ s.add_dependency 'tvdb_party', '~> 0.6.0'
18
+ s.add_development_dependency 'rspec', '~> 2.0'
19
+
20
+ s.files = `git ls-files`.split("\n")
21
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
22
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
23
+ s.require_paths = ["lib"]
24
+ end
metadata ADDED
@@ -0,0 +1,114 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: unified_db
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Bernard Potocki
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-08-22 00:00:00.000000000 +02:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: yajl-ruby
17
+ requirement: &70343143888220 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *70343143888220
26
+ - !ruby/object:Gem::Dependency
27
+ name: imdb_party
28
+ requirement: &70343143887680 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 0.6.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: *70343143887680
37
+ - !ruby/object:Gem::Dependency
38
+ name: tvdb_party
39
+ requirement: &70343143887140 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ version: 0.6.0
45
+ type: :runtime
46
+ prerelease: false
47
+ version_requirements: *70343143887140
48
+ - !ruby/object:Gem::Dependency
49
+ name: rspec
50
+ requirement: &70343143886640 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ~>
54
+ - !ruby/object:Gem::Version
55
+ version: '2.0'
56
+ type: :development
57
+ prerelease: false
58
+ version_requirements: *70343143886640
59
+ description: Scrapper for multiple Movie Databases
60
+ email:
61
+ - bernard.potocki@imanel.org
62
+ executables: []
63
+ extensions: []
64
+ extra_rdoc_files: []
65
+ files:
66
+ - .gitignore
67
+ - Gemfile
68
+ - README.md
69
+ - Rakefile
70
+ - lib/ext/crack.rb
71
+ - lib/unified_db.rb
72
+ - lib/unified_db/api_error.rb
73
+ - lib/unified_db/backend.rb
74
+ - lib/unified_db/backend/base.rb
75
+ - lib/unified_db/backend/imdb.rb
76
+ - lib/unified_db/backend/tvdb.rb
77
+ - lib/unified_db/result.rb
78
+ - lib/unified_db/result/base.rb
79
+ - lib/unified_db/result/id.rb
80
+ - lib/unified_db/result/title.rb
81
+ - lib/unified_db/version.rb
82
+ - spec/spec_helper.rb
83
+ - spec/unified_db/backend/imdb_spec.rb
84
+ - spec/unified_db/backend/tvdb_spec.rb
85
+ - unified_db.gemspec
86
+ has_rdoc: true
87
+ homepage: http://github.com/imanel/unifieddb
88
+ licenses: []
89
+ post_install_message:
90
+ rdoc_options: []
91
+ require_paths:
92
+ - lib
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ none: false
101
+ requirements:
102
+ - - ! '>='
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ requirements: []
106
+ rubyforge_project:
107
+ rubygems_version: 1.6.2
108
+ signing_key:
109
+ specification_version: 3
110
+ summary: Scrapper for multiple Movie Databases
111
+ test_files:
112
+ - spec/spec_helper.rb
113
+ - spec/unified_db/backend/imdb_spec.rb
114
+ - spec/unified_db/backend/tvdb_spec.rb