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
+39
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
+13
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
+15
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
+23
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
+9
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
+5
View File
@@ -0,0 +1,5 @@
module Robbie
class Genre < BaseModel
attr_accessor :id, :name
end
end
+5
View File
@@ -0,0 +1,5 @@
module Robbie
class Track < BaseModel
attr_accessor :id, :disc_id, :position, :artists, :title, :duration
end
end
+48
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
+40
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
+41
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
+45
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
+34
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
View File
@@ -0,0 +1,3 @@
module Robbie
VERSION = "0.0.1"
end