1
0
Fork 0

Robbie comes in

This commit is contained in:
Gregory Eremin 2012-08-26 08:09:00 +04:00
commit d2cb07cb4e
20 changed files with 462 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
tmp

3
Gemfile Normal file
View File

@ -0,0 +1,3 @@
source :rubygems
gemspec

22
Gemfile.lock Normal file
View File

@ -0,0 +1,22 @@
PATH
remote: .
specs:
robbie (0.0.1)
httparty
oj
GEM
remote: http://rubygems.org/
specs:
httparty (0.8.3)
multi_json (~> 1.0)
multi_xml
multi_json (1.3.6)
multi_xml (0.5.1)
oj (1.3.4)
PLATFORMS
ruby
DEPENDENCIES
robbie!

22
LICENSE Normal file
View File

@ -0,0 +1,22 @@
Copyright (c) 2012 Gregory Eremin
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

71
README.md Normal file
View File

@ -0,0 +1,71 @@
# Robbie
Rovi API wrapper
## Installation
Add this line to your application's Gemfile:
```ruby
gem "robbie"
```
And then execute:
```bash
$ bundle
```
Or install it yourself as:
```bash
$ gem install robbie
```
## Usage
*Working with models*
```ruby
require "robbie"
Robbie.setup(api_key: "your api key", api_secret: "your api secret")
foo = Robbie::Artist.find_by_name("foo fighters")
# <Robbie::Artist:0x007fb9cbd7c120 @id="MA0000002613", @name="Foo Fighters", @is_group=true, @genres=[#<Robbie::Genre:0x007fb9cbd7c2b0 @id="MA0000002613", @name="Pop/Rock">]>
# ...or directly by id
foo = Robbie::Artist.find_by_name("MA0000002613")
foo.albums.last
# <Robbie::Album:0x007fb9cc16b790 @id="MW0002115022", @title="Wasting Light">
# ...or directly by id
Robbie::Album.find("MW0002115022")
foo.albums.last.tracks.first
# <Robbie::Track:0x007fa633a39540 @id="MT0041016087", @disc_id=1, @position=1, @artists=[#<Robbie::Artist:0x007fa633a397e8 @id="MN0000184043", @name="Foo Fighters">], @title="Bridge Burning", @duration=286>
# ...or directly by id
Robbie::Track.find("MT0041016087")
```
Autocomplete and extended autocomplete
```ruby
Robbie::Autocomplete.complete("b")
# ["Beyoncé", "Bruno Mars", "Bad Meets Evil", "Bon Iver", "Bob Marley", "Big Sean", "The Band Perry", "Blake Shelton", "B.O.B", "The Black Eyed Peas"]
Robbie::Autocomplete.predict("b").first
# <Robbie::Artist:0x007fa633b31ba0 @id="MN0000761179", @name="Beyoncé", @is_group=false, @genres=[#<Robbie::Genre:0x007fa633b31e48 @id="MA0000002809", @name="R&B">]>
```
*You can turn response caching*
```ruby
# on
Robbie.enable_cache
# and off
Robbie.disable_cache
```
## Contributing
1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Added some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request

2
Rakefile Normal file
View File

@ -0,0 +1,2 @@
#!/usr/bin/env rake
require "bundler/gem_tasks"

39
lib/robbie.rb Normal file
View File

@ -0,0 +1,39 @@
require "digest/md5"
require "httparty"
require "oj"
require "multi_json"
require "robbie/version"
require "robbie/parsers/base_parser"
require "robbie/parsers/search"
require "robbie/parsers/artist"
require "robbie/parsers/album"
require "robbie/parsers/track"
require "robbie/models/base_model"
require "robbie/models/artist"
require "robbie/models/album"
require "robbie/models/track"
require "robbie/models/genre"
require "robbie/autocomplete"
module Robbie
@@cache_enabled = true
class << self
def setup(params)
const_set(:API_KEY, params[:api_key])
const_set(:API_SECRET, params[:api_secret])
end
def enable_cache
@@cache_enabled = true
end
def disable_cache
@@cache_enabled = false
end
def cache_enabled?
@@cache_enabled
end
end
end

View File

@ -0,0 +1,13 @@
module Robbie
class Autocomplete
class << self
def complete(q)
Parsers::Search.autocomplete(q)
end
def predict(q)
Parsers::Search.single_stage_search(q)
end
end
end
end

View File

@ -0,0 +1,15 @@
module Robbie
class Album < BaseModel
attr_accessor :id, :title, :year, :tracks
class << self
def search(q)
Parsers::Search.search(q).keep_if { |item| item.instance_of?(Robbie::Album) }
end
end
def tracks
@tracks ||= Parsers::Album.find(id).tracks
end
end
end

View File

@ -0,0 +1,23 @@
module Robbie
class Artist < BaseModel
attr_accessor :id, :name, :is_group, :genres, :albums
class << self
def search(q)
Parsers::Search.search(q).keep_if { |item| item.instance_of?(Robbie::Artist) }
end
def find_by_name(name)
search(name).first
end
def find(id)
Parsers::Artist.find(id)
end
end
def albums
@albums ||= Parsers::Artist.find(id).albums
end
end
end

View File

@ -0,0 +1,9 @@
module Robbie
class BaseModel
def initialize(values)
values.each do |key, val|
send(:"#{key}=", val)
end
end
end
end

View File

@ -0,0 +1,5 @@
module Robbie
class Genre < BaseModel
attr_accessor :id, :name
end
end

View File

@ -0,0 +1,5 @@
module Robbie
class Track < BaseModel
attr_accessor :id, :disc_id, :position, :artists, :title, :duration
end
end

View File

@ -0,0 +1,48 @@
module Robbie
module Parsers
class Album < BaseParser
class << self
def find(album_id)
response = query("/data/v1/album/info", {
albumid: album_id,
include: "tracks"
})
parse(response["album"])
end
def parse(data)
return if data.nil?
album = parse_meta(data)
if data["tracks"].is_a?(Array)
current_disc = 0
position = 0
album.tracks = data["tracks"].map do |track|
if track["disc"] && track["disc"] != current_disc
position = 0
current_disc = track["disc"]
end
position += 1
Parsers::Track.parse_meta(track, current_disc, position)
end
end
album
end
def parse_meta(data)
return if data.nil?
params = {}
params[:id] = data["ids"]["albumId"] if data["ids"]
params[:title] = data["title"]
if data["album"] && data["originalReleaseDate"].is_a?(String)
params[:year] = data["originalReleaseDate"].split("-").first
end
Robbie::Album.new(params)
end
end
end
end
end

View File

@ -0,0 +1,40 @@
module Robbie
module Parsers
class Artist < BaseParser
class << self
def find(artist_id)
response = query("/data/v1/name/info", {
nameid: artist_id,
include: "discography",
type: "main"
})
parse(response["name"])
end
def parse(data)
return if data.nil?
artist = parse_meta(data)
if data["discography"] && data["discography"].is_a?(Array)
artist.albums = data["discography"].map{ |album| Parsers::Album.parse_meta(album) }.reverse
end
artist
end
def parse_meta(data)
return if data.nil?
params = {}
params[:id] = data["ids"]["nameId"] if data["ids"]
params[:name] = data["name"]
params[:is_group] = data["isGroup"]
params[:genres] = data["musicGenres"].map{ |genre|
Robbie::Genre.new(id: genre["id"], name: genre["name"])
} if data["musicGenres"].is_a?(Array)
Robbie::Artist.new(params)
end
end
end
end
end

View File

@ -0,0 +1,41 @@
module Robbie
module Parsers
class BaseParser
include HTTParty
base_uri "api.rovicorp.com"
format :json
class << self
def sig
Digest::MD5.hexdigest("#{API_KEY}#{API_SECRET}#{Time.now.to_i}")
end
def query(path, params)
unless Robbie.const_defined?(:API_KEY) and Robbie.const_defined?(:API_SECRET)
raise Exception.new("No API credentials given")
end
params_str = params
.merge({ apikey: API_KEY, sig: sig, format: "json" })
.map{ |key, val| "#{key}=#{val}" }.join("&")
if Robbie.cache_enabled?
cache_key = "#{path}?#{params.inspect}".scan(/\w/).join
cache_file = File.expand_path("../../../../tmp/cache/#{cache_key}", __FILE__)
if File.exist?(cache_file)
MultiJson.load(File.open(cache_file).read)
else
data = get("#{path}?#{params_str}")
File.open(cache_file, "w") do |file|
file.write(MultiJson.dump(data)) unless data.nil? or data.empty?
end
data
end
else
get("#{path}?#{params_str}")
end
end
end
end
end
end

View File

@ -0,0 +1,45 @@
module Robbie
module Parsers
class Search < BaseParser
class << self
def search(q)
response = query("/search/v2.1/music/search", {
query: q.gsub(" ", "%20"),
entitytype: "artist&entitytype=album"
})
parse(response["searchResponse"]["results"])
end
def single_stage_search(q)
response = query("/search/v2.1/music/singlestagesearch", {
query: q.gsub(" ", "%20"),
entitytype: "artist&entitytype=album",
size: 10
})
parse(response["searchResponse"]["results"])
end
def parse(data)
return if data.nil?
data.map do |result|
if result["type"] == "artist"
Parsers::Artist.parse_meta(result["name"])
elsif result["type"] == "album"
Parsers::Album.parse_meta(result["album"])
end
end
end
def autocomplete(q)
response = query("/search/v2.1/music/autocomplete", {
query: q.gsub(" ", "%20"),
entitytype: "artist&entitytype=album",
size: 10
})
response["autocompleteResponse"]["results"]
end
end
end
end
end

View File

@ -0,0 +1,34 @@
module Robbie
module Parsers
class Track < BaseParser
class << self
def find(track_id)
response = query("/data/v1/song/info", {
trackid: track_id
})
parse_meta(response["song"])
end
def parse_meta(data, disc = nil, position = nil)
return if data.nil?
params = {}
params[:id] = data["ids"]["trackId"] if data["ids"]
params[:disc_id] = disc
params[:position] = position
params[:artists] = data["performers"].map{ |performer|
Robbie::Artist.new(id: performer["id"], name: performer["name"])
} if data["performers"].is_a?(Array)
params[:artists] = data["primaryArtists"].map{ |artist|
Robbie::Artist.new(id: artist["id"], name: artist["name"])
} if data["primaryArtists"].is_a?(Array)
params[:title] = data["title"]
params[:duration] = data["duration"]
Robbie::Track.new(params)
end
end
end
end
end

3
lib/robbie/version.rb Normal file
View File

@ -0,0 +1,3 @@
module Robbie
VERSION = "0.0.1"
end

21
robbie.gemspec Normal file
View File

@ -0,0 +1,21 @@
# encoding: UTF-8
require File.expand_path('../lib/robbie/version', __FILE__)
Gem::Specification.new do |gem|
gem.authors = ["Gregory Eremin"]
gem.email = %w[ magnolia_fan@me.com ]
gem.description = %q{ Rovi API wrapper }
gem.summary = %q{ Rovi API wrapper }
gem.homepage = "https://github.com/magnolia-fan/robbie"
gem.files = %x{ git ls-files }.split($\)
gem.executables = gem.files.grep(%r{^bin/}).map{ |file| File.basename(file) }
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
gem.name = "robbie"
gem.require_paths = %w[ lib ]
gem.version = Robbie::VERSION
gem.platform = Gem::Platform::RUBY
gem.add_dependency "httparty"
gem.add_dependency "oj"
end