Robbie comes in
This commit is contained in:
commit
d2cb07cb4e
|
@ -0,0 +1 @@
|
||||||
|
tmp
|
|
@ -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!
|
|
@ -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.
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,9 @@
|
||||||
|
module Robbie
|
||||||
|
class BaseModel
|
||||||
|
def initialize(values)
|
||||||
|
values.each do |key, val|
|
||||||
|
send(:"#{key}=", val)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
module Robbie
|
||||||
|
class Genre < BaseModel
|
||||||
|
attr_accessor :id, :name
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
module Robbie
|
||||||
|
class Track < BaseModel
|
||||||
|
attr_accessor :id, :disc_id, :position, :artists, :title, :duration
|
||||||
|
end
|
||||||
|
end
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,3 @@
|
||||||
|
module Robbie
|
||||||
|
VERSION = "0.0.1"
|
||||||
|
end
|
|
@ -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
|
Loading…
Reference in New Issue