Mass rewrite
This commit is contained in:
parent
3bf68d152e
commit
7c42a90a6c
5
.gitignore
vendored
5
.gitignore
vendored
@ -1,8 +1,5 @@
|
|||||||
coverage
|
coverage
|
||||||
rdoc
|
|
||||||
doc
|
|
||||||
.yardoc
|
|
||||||
.bundle
|
.bundle
|
||||||
pkg
|
|
||||||
tmp
|
tmp
|
||||||
Gemfile.lock
|
Gemfile.lock
|
||||||
|
.gem
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
rvm:
|
rvm:
|
||||||
- 1.8.7
|
|
||||||
- 1.9.2
|
- 1.9.2
|
||||||
- 1.9.3
|
- 1.9.3
|
||||||
|
@ -3,3 +3,4 @@ Huge thanks to that people for making this gem better!
|
|||||||
Applicat (https://github.com/Applicat)
|
Applicat (https://github.com/Applicat)
|
||||||
Jens Fahnenbruck (https://github.com/jigfox)
|
Jens Fahnenbruck (https://github.com/jigfox)
|
||||||
Sander Nieuwenhuizen (https://github.com/munkius)
|
Sander Nieuwenhuizen (https://github.com/munkius)
|
||||||
|
Savater Sebastien (https://github.com/blakink)
|
||||||
|
13
Rakefile
13
Rakefile
@ -1,13 +0,0 @@
|
|||||||
#!/usr/bin/env rake
|
|
||||||
require "bundler/gem_tasks"
|
|
||||||
require "rspec/core/rake_task"
|
|
||||||
|
|
||||||
RSpec::Core::RakeTask.new("spec")
|
|
||||||
|
|
||||||
task :default => :spec
|
|
||||||
task :test => :spec
|
|
||||||
|
|
||||||
desc "Open an irb session preloaded with this library"
|
|
||||||
task :console do
|
|
||||||
sh "irb -rubygems -I lib -r musicbrainz.rb"
|
|
||||||
end
|
|
@ -1,25 +0,0 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
|
||||||
|
|
||||||
module MusicBrainz
|
|
||||||
class << self
|
|
||||||
def query_interval
|
|
||||||
$stdout.send :puts, "WARNING! MusicBrainz.query_interval is deprecated. Use MusicBrainz::Tools::Proxy.query_interval"
|
|
||||||
MusicBrainz::Tools::Proxy.query_interval
|
|
||||||
end
|
|
||||||
|
|
||||||
def query_interval=(sec)
|
|
||||||
$stdout.send :puts, "WARNING! MusicBrainz.query_interval= is deprecated. Use MusicBrainz::Tools::Proxy.query_interval"
|
|
||||||
MusicBrainz::Tools::Proxy.query_interval = sec
|
|
||||||
end
|
|
||||||
|
|
||||||
def cache_path
|
|
||||||
$stdout.send :puts, "WARNING! MusicBrainz.cache_path is deprecated. Use MusicBrainz::Tools::Cache.cache_path"
|
|
||||||
MusicBrainz::Tools::Cache.cache_path
|
|
||||||
end
|
|
||||||
|
|
||||||
def cache_path=(path)
|
|
||||||
$stdout.send :puts, "WARNING! MusicBrainz.cache_path= is deprecated. Use MusicBrainz::Tools::Cache.cache_path"
|
|
||||||
MusicBrainz::Tools::Cache.cache_path = path
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,30 +1,34 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
require "digest/sha1"
|
||||||
|
require "fileutils"
|
||||||
|
|
||||||
require "open-uri"
|
require "faraday"
|
||||||
require "socket"
|
|
||||||
require "nokogiri"
|
require "nokogiri"
|
||||||
require "cgi"
|
|
||||||
|
require "musicbrainz/version"
|
||||||
|
require "musicbrainz/deprecated"
|
||||||
|
require "musicbrainz/middleware"
|
||||||
|
require "musicbrainz/configuration"
|
||||||
|
|
||||||
|
require "musicbrainz/client_modules/transparent_proxy"
|
||||||
|
require "musicbrainz/client_modules/failsafe_proxy"
|
||||||
|
require "musicbrainz/client_modules/caching_proxy"
|
||||||
|
require "musicbrainz/client"
|
||||||
|
|
||||||
|
require "musicbrainz/models/base_model"
|
||||||
|
require "musicbrainz/models/artist"
|
||||||
|
require "musicbrainz/models/release_group"
|
||||||
|
require "musicbrainz/models/release"
|
||||||
|
require "musicbrainz/models/track"
|
||||||
|
|
||||||
|
require "musicbrainz/bindings/artist"
|
||||||
|
require "musicbrainz/bindings/artist_search"
|
||||||
|
require "musicbrainz/bindings/artist_release_groups"
|
||||||
|
require "musicbrainz/bindings/release_group"
|
||||||
|
require "musicbrainz/bindings/release_group_releases"
|
||||||
|
require "musicbrainz/bindings/release"
|
||||||
|
require "musicbrainz/bindings/release_tracks"
|
||||||
|
require "musicbrainz/bindings/track"
|
||||||
|
|
||||||
module MusicBrainz
|
module MusicBrainz
|
||||||
module Tools; end
|
GH_PAGE_URL = "http://git.io/brainz"
|
||||||
module Parsers; end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
require "version"
|
|
||||||
require "deprecated"
|
|
||||||
|
|
||||||
require "musicbrainz/base"
|
|
||||||
require "musicbrainz/artist"
|
|
||||||
require "musicbrainz/release_group"
|
|
||||||
require "musicbrainz/release"
|
|
||||||
require "musicbrainz/track"
|
|
||||||
|
|
||||||
require "tools/configuration"
|
|
||||||
require "tools/cache"
|
|
||||||
require "tools/proxy"
|
|
||||||
|
|
||||||
require "parsers/base"
|
|
||||||
require "parsers/artist"
|
|
||||||
require "parsers/release_group"
|
|
||||||
require "parsers/release"
|
|
||||||
require "parsers/track"
|
|
||||||
|
@ -1,63 +0,0 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
|
||||||
|
|
||||||
module MusicBrainz
|
|
||||||
class Artist < Base
|
|
||||||
|
|
||||||
field :id, String
|
|
||||||
field :type, String
|
|
||||||
field :name, String
|
|
||||||
field :country, String
|
|
||||||
field :date_begin, Time
|
|
||||||
field :date_end, Time
|
|
||||||
field :urls, Hash
|
|
||||||
|
|
||||||
def release_groups
|
|
||||||
@release_groups ||= nil
|
|
||||||
if @release_groups.nil? and !id.nil?
|
|
||||||
@release_groups = self.class.load({
|
|
||||||
:parser => :artist_release_groups,
|
|
||||||
:create_models => MusicBrainz::ReleaseGroup
|
|
||||||
}, {
|
|
||||||
:resource => :release_group,
|
|
||||||
:artist => id
|
|
||||||
})
|
|
||||||
@release_groups.sort!{ |a, b| a.first_release_date <=> b.first_release_date }
|
|
||||||
end
|
|
||||||
@release_groups
|
|
||||||
end
|
|
||||||
|
|
||||||
class << self
|
|
||||||
def find(mbid)
|
|
||||||
load({
|
|
||||||
:parser => :artist_model,
|
|
||||||
:create_model => MusicBrainz::Artist
|
|
||||||
}, {
|
|
||||||
:resource => :artist,
|
|
||||||
:id => mbid,
|
|
||||||
:inc => [:url_rels]
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
def search(name)
|
|
||||||
load({
|
|
||||||
:parser => :artist_search
|
|
||||||
}, {
|
|
||||||
:resource => :artist,
|
|
||||||
:query => "artist:" << CGI.escape(name).gsub(/\!/, '\!'),
|
|
||||||
:limit => 10
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
def discography(mbid)
|
|
||||||
artist = find(mbid)
|
|
||||||
artist.release_groups.each { |rg| rg.releases.each { |r| r.tracks } }
|
|
||||||
artist
|
|
||||||
end
|
|
||||||
|
|
||||||
def find_by_name(name)
|
|
||||||
matches = search(name)
|
|
||||||
matches.length.zero? ? nil : find(matches.first[:mbid])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,71 +0,0 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
|
||||||
|
|
||||||
module MusicBrainz
|
|
||||||
class Base
|
|
||||||
class << self
|
|
||||||
def field(name, type)
|
|
||||||
@fields ||= {}
|
|
||||||
@fields[name] = type
|
|
||||||
|
|
||||||
define_method(name) {
|
|
||||||
instance_variable_get("@#{name}")
|
|
||||||
}
|
|
||||||
define_method("#{name}=") { |val|
|
|
||||||
instance_variable_set("@#{name}", validate_type(val, type))
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def load(params, query)
|
|
||||||
parser = MusicBrainz::Parsers.get_by_name(params[:parser])
|
|
||||||
xml = MusicBrainz::Tools::Proxy.query(query)
|
|
||||||
result = parser[:const].send(parser[:method], Nokogiri::XML(xml))
|
|
||||||
if params[:create_model]
|
|
||||||
result_model = params[:create_model].new
|
|
||||||
result.each { |field, value|
|
|
||||||
result_model.send("#{field}=".to_sym, value)
|
|
||||||
}
|
|
||||||
result_model
|
|
||||||
elsif params[:create_models]
|
|
||||||
result_models = []
|
|
||||||
result.each { |item|
|
|
||||||
result_model = params[:create_models].new
|
|
||||||
item.each { |field, value|
|
|
||||||
result_model.send("#{field}=".to_sym, value)
|
|
||||||
}
|
|
||||||
result_models << result_model
|
|
||||||
}
|
|
||||||
result_models
|
|
||||||
else
|
|
||||||
result
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def initialize
|
|
||||||
self.class.instance_variable_get("@fields").each { |name, type|
|
|
||||||
instance_variable_set("@#{name}", nil)
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def validate_type(val, type)
|
|
||||||
if type == Integer
|
|
||||||
val.to_i
|
|
||||||
elsif type == Float
|
|
||||||
val.to_f
|
|
||||||
elsif type == String
|
|
||||||
val.to_s
|
|
||||||
elsif type == Time
|
|
||||||
if val.nil? or val == ""
|
|
||||||
val = "2030-12-31"
|
|
||||||
elsif val.split("-").length == 1
|
|
||||||
val << "-12-31"
|
|
||||||
elsif val.split("-").length == 2
|
|
||||||
val << "-31"
|
|
||||||
end
|
|
||||||
Time.utc(*val.split("-"))
|
|
||||||
else
|
|
||||||
val
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
23
lib/musicbrainz/bindings/artist.rb
Normal file
23
lib/musicbrainz/bindings/artist.rb
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# encoding: UTF-8
|
||||||
|
module MusicBrainz
|
||||||
|
module Bindings
|
||||||
|
module Artist
|
||||||
|
def parse(xml)
|
||||||
|
xml = xml.xpath('./artist') unless xml.xpath('./artist').empty?
|
||||||
|
{
|
||||||
|
id: (xml.attribute('id').value rescue nil),
|
||||||
|
type: (xml.attribute('type').value rescue nil),
|
||||||
|
name: (xml.xpath('./name').text.gsub(/[`’]/, "'") rescue nil),
|
||||||
|
country: (xml.xpath('./country').text rescue nil),
|
||||||
|
date_begin: (xml.xpath('./life-span/begin').text rescue nil),
|
||||||
|
date_end: (xml.xpath('./life-span/end').text rescue nil),
|
||||||
|
urls: (Hash[xml.xpath('./relation-list[@target-type="url"]/relation').map{ |xml|
|
||||||
|
[xml.attribute('type').value.downcase.split(" ").join("_").to_sym, xml.xpath('./target').text]
|
||||||
|
}] rescue {})
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
extend self
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
13
lib/musicbrainz/bindings/artist_release_groups.rb
Normal file
13
lib/musicbrainz/bindings/artist_release_groups.rb
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
module MusicBrainz
|
||||||
|
module Bindings
|
||||||
|
module ArtistReleaseGroups
|
||||||
|
def parse(xml)
|
||||||
|
xml.xpath('./release-group-list/release-group').map do |xml|
|
||||||
|
MusicBrainz::Bindings::ReleaseGroup.parse(xml)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
extend self
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
23
lib/musicbrainz/bindings/artist_search.rb
Normal file
23
lib/musicbrainz/bindings/artist_search.rb
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# encoding: UTF-8
|
||||||
|
module MusicBrainz
|
||||||
|
module Bindings
|
||||||
|
module ArtistSearch
|
||||||
|
def parse(xml)
|
||||||
|
xml.xpath('./artist-list/artist').map do |xml|
|
||||||
|
{
|
||||||
|
id: (xml.attribute('id').value rescue nil),
|
||||||
|
mbid: (xml.attribute('id').value rescue nil), # Old shit
|
||||||
|
name: (xml.xpath('./name').text.gsub(/[`’]/, "'") rescue nil),
|
||||||
|
sort_name: (xml.xpath('./sort-name').gsub(/[`’]/, "'") rescue nil),
|
||||||
|
type: (xml.attribute('type').value rescue nil),
|
||||||
|
score: (xml.attribute('score').value.to_i rescue nil),
|
||||||
|
desc: (xml.xpath('./disambiguation').value rescue nil),
|
||||||
|
aliases: (xml.xpath('./alias-list/alias').map{ |xml| xml.text } rescue [])
|
||||||
|
} rescue nil
|
||||||
|
end.delete_if{ |item| item.nil? }
|
||||||
|
end
|
||||||
|
|
||||||
|
extend self
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
19
lib/musicbrainz/bindings/release.rb
Normal file
19
lib/musicbrainz/bindings/release.rb
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
module MusicBrainz
|
||||||
|
module Bindings
|
||||||
|
module Release
|
||||||
|
def parse(xml)
|
||||||
|
xml = xml.xpath('./release') unless xml.xpath('./release').empty?
|
||||||
|
{
|
||||||
|
id: (xml.attribute('id').value rescue nil),
|
||||||
|
title: (xml.xpath('./title').text rescue nil),
|
||||||
|
status: (xml.xpath('./status').text rescue nil),
|
||||||
|
country: (xml.xpath('./country').text rescue nil),
|
||||||
|
format: (xml.xpath('./medium-list/medium/format').text rescue nil),
|
||||||
|
date: (xml.xpath('./date').text rescue nil)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
extend self
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
18
lib/musicbrainz/bindings/release_group.rb
Normal file
18
lib/musicbrainz/bindings/release_group.rb
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
module MusicBrainz
|
||||||
|
module Bindings
|
||||||
|
module ReleaseGroup
|
||||||
|
def parse(xml)
|
||||||
|
xml = xml.xpath('./release-group') unless xml.xpath('./release-group').empty?
|
||||||
|
{
|
||||||
|
id: (xml.attribute('id').value rescue nil),
|
||||||
|
type: (xml.attribute('type').value rescue nil),
|
||||||
|
title: (xml.xpath('./title').text rescue nil),
|
||||||
|
desc: (xml.xpath('./disambiguation').text rescue nil),
|
||||||
|
first_release_date: (xml.xpath('./first-release-date').text rescue nil)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
extend self
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
13
lib/musicbrainz/bindings/release_group_releases.rb
Normal file
13
lib/musicbrainz/bindings/release_group_releases.rb
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
module MusicBrainz
|
||||||
|
module Bindings
|
||||||
|
module ReleaseGroupReleases
|
||||||
|
def parse(xml)
|
||||||
|
xml.xpath('./release-list/release').map do |xml|
|
||||||
|
MusicBrainz::Bindings::Release.parse(xml)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
extend self
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
13
lib/musicbrainz/bindings/release_tracks.rb
Normal file
13
lib/musicbrainz/bindings/release_tracks.rb
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
module MusicBrainz
|
||||||
|
module Bindings
|
||||||
|
module ReleaseTracks
|
||||||
|
def parse(xml)
|
||||||
|
xml.xpath('./release/medium-list/medium/track-list/track').map do |xml|
|
||||||
|
MusicBrainz::Bindings::Track.parse(xml)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
extend self
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
16
lib/musicbrainz/bindings/track.rb
Normal file
16
lib/musicbrainz/bindings/track.rb
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
module MusicBrainz
|
||||||
|
module Bindings
|
||||||
|
module Track
|
||||||
|
def parse(xml)
|
||||||
|
{
|
||||||
|
position: (xml.xpath('./position').text rescue nil),
|
||||||
|
recording_id: (xml.xpath('./recording').attribute('id').value rescue nil),
|
||||||
|
title: (xml.xpath('./recording/title').text rescue nil),
|
||||||
|
length: (xml.xpath('./recording/length').text rescue nil)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
extend self
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
67
lib/musicbrainz/client.rb
Normal file
67
lib/musicbrainz/client.rb
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
module MusicBrainz
|
||||||
|
module Client
|
||||||
|
def http
|
||||||
|
@faraday ||= Faraday.new do |f|
|
||||||
|
f.request :url_encoded # form-encode POST params
|
||||||
|
f.adapter Faraday.default_adapter # make requests with Net::HTTP
|
||||||
|
f.use MusicBrainz::Middleware # run requests with correct headers
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def load(resource, query, params)
|
||||||
|
response = contents_of(build_url(resource, query))
|
||||||
|
xml = Nokogiri::XML.parse(response).remove_namespaces!.xpath('/metadata')
|
||||||
|
data = params[:binding].parse(xml)
|
||||||
|
|
||||||
|
if params[:create_model]
|
||||||
|
result_model = params[:create_model].new
|
||||||
|
data.each do |field, value|
|
||||||
|
result_model.send("#{field}=".to_sym, value)
|
||||||
|
end
|
||||||
|
result_model
|
||||||
|
elsif params[:create_models]
|
||||||
|
result_models = []
|
||||||
|
data.each do |item|
|
||||||
|
result_model = params[:create_models].new
|
||||||
|
item.each do |field, value|
|
||||||
|
result_model.send("#{field}=".to_sym, value)
|
||||||
|
end
|
||||||
|
result_models << result_model
|
||||||
|
end
|
||||||
|
if params[:sort]
|
||||||
|
result_models.sort!{ |a, b| a.send(params[:sort]) <=> b.send(params[:sort]) }
|
||||||
|
end
|
||||||
|
result_models
|
||||||
|
else
|
||||||
|
data
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def contents_of(url)
|
||||||
|
if method_defined? :get_contents
|
||||||
|
get_contents url
|
||||||
|
else
|
||||||
|
http.get url
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_url(resource, params)
|
||||||
|
"#{MusicBrainz.config.web_service_url}#{resource.to_s.gsub('_', '-')}" <<
|
||||||
|
((id = params.delete(:id)) ? "/#{id}?" : "?") <<
|
||||||
|
params.map do |key, value|
|
||||||
|
key = key.to_s.gsub('_', '-')
|
||||||
|
value = if value.is_a?(Array)
|
||||||
|
value.map{ |el| el.to_s.gsub('_', '-') }.join('+')
|
||||||
|
else
|
||||||
|
value.to_s
|
||||||
|
end
|
||||||
|
"#{key}=#{value}"
|
||||||
|
end.join('&')
|
||||||
|
end
|
||||||
|
|
||||||
|
include ClientModules::TransparentProxy
|
||||||
|
include ClientModules::FailsafeProxy
|
||||||
|
include ClientModules::CachingProxy
|
||||||
|
extend self
|
||||||
|
end
|
||||||
|
end
|
38
lib/musicbrainz/client_modules/caching_proxy.rb
Normal file
38
lib/musicbrainz/client_modules/caching_proxy.rb
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
module MusicBrainz
|
||||||
|
module ClientModules
|
||||||
|
module CachingProxy
|
||||||
|
def cache_path
|
||||||
|
MusicBrainz.config.cache_path
|
||||||
|
end
|
||||||
|
|
||||||
|
def clear_cache
|
||||||
|
FileUtils.rm_r(cache_path) if cache_path && File.exist?(cache_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_contents(url)
|
||||||
|
return super unless MusicBrainz.config.perform_caching
|
||||||
|
|
||||||
|
token = Digest::SHA256.hexdigest(url)
|
||||||
|
file_path = "#{cache_path}/#{token[0..1]}/#{token[2..3]}/#{token[4..-1]}.xml"
|
||||||
|
|
||||||
|
response = nil
|
||||||
|
|
||||||
|
if File.exist?(file_path)
|
||||||
|
response = File.open(file_path).gets
|
||||||
|
else
|
||||||
|
response = super
|
||||||
|
unless response.nil? or response.empty?
|
||||||
|
FileUtils.mkdir_p file_path.split('/')[0..-2].join('/')
|
||||||
|
File.open(file_path, 'w') do |f|
|
||||||
|
f.puts response
|
||||||
|
f.chmod 0755
|
||||||
|
f.close
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
response
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
23
lib/musicbrainz/client_modules/failsafe_proxy.rb
Normal file
23
lib/musicbrainz/client_modules/failsafe_proxy.rb
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
module MusicBrainz
|
||||||
|
module ClientModules
|
||||||
|
module FailsafeProxy
|
||||||
|
def get_contents(url)
|
||||||
|
response = nil
|
||||||
|
|
||||||
|
MusicBrainz.config.tries_limit.times do
|
||||||
|
time_passed = Time.now.to_f - @last_query_time ||= 0.0
|
||||||
|
if time_passed < MusicBrainz.config.query_interval
|
||||||
|
sleep(MusicBrainz.config.query_interval - time_passed)
|
||||||
|
end
|
||||||
|
|
||||||
|
response = super
|
||||||
|
@last_query_time = Time.now.to_f
|
||||||
|
|
||||||
|
break if response.status == 200
|
||||||
|
end
|
||||||
|
|
||||||
|
response.body rescue nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
9
lib/musicbrainz/client_modules/transparent_proxy.rb
Normal file
9
lib/musicbrainz/client_modules/transparent_proxy.rb
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
module MusicBrainz
|
||||||
|
module ClientModules
|
||||||
|
module TransparentProxy
|
||||||
|
def get_contents(url)
|
||||||
|
http.get url
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
42
lib/musicbrainz/configuration.rb
Normal file
42
lib/musicbrainz/configuration.rb
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
module MusicBrainz
|
||||||
|
class Configuration
|
||||||
|
attr_accessor :app_name, :app_version, :contact,
|
||||||
|
:web_service_url,
|
||||||
|
:query_interval, :tries_limit,
|
||||||
|
:cache_path, :perform_caching
|
||||||
|
|
||||||
|
DEFAULT_WEB_SERVICE_URL = "http://musicbrainz.org/ws/2/"
|
||||||
|
DEFAULT_QUERY_INTERVAL = 1.5
|
||||||
|
DEFAULT_TRIES_LIMIT = 5
|
||||||
|
DEFAULT_CACHE_PATH = File.join(File.dirname(__FILE__), "..", "tmp", "cache")
|
||||||
|
DEFAULT_PERFORM_CACHING = false
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
@web_service_url = DEFAULT_WEB_SERVICE_URL
|
||||||
|
@query_interval = DEFAULT_QUERY_INTERVAL
|
||||||
|
@tries_limit = DEFAULT_TRIES_LIMIT
|
||||||
|
@cache_path = DEFAULT_CACHE_PATH
|
||||||
|
@perform_caching = DEFAULT_PERFORM_CACHING
|
||||||
|
end
|
||||||
|
|
||||||
|
def user_agent_string
|
||||||
|
%w[ app_name app_version contact ].each do |param|
|
||||||
|
raise "#{param} must be set" if instance_variable_get("@#{param}").nil?
|
||||||
|
end
|
||||||
|
|
||||||
|
"#{@app_name}/#{@app_version} ( #{@contact} )"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module Configurable
|
||||||
|
def configure
|
||||||
|
raise "Configuration missing" unless block_given?
|
||||||
|
yield @config ||= MusicBrainz::Configuration.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def config
|
||||||
|
@config
|
||||||
|
end
|
||||||
|
end
|
||||||
|
extend Configurable
|
||||||
|
end
|
45
lib/musicbrainz/deprecated.rb
Normal file
45
lib/musicbrainz/deprecated.rb
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
module MusicBrainz
|
||||||
|
def query_interval
|
||||||
|
MusicBrainz.config.query_interval
|
||||||
|
end
|
||||||
|
|
||||||
|
def query_interval=(value)
|
||||||
|
MusicBrainz.config.query_interval = value
|
||||||
|
end
|
||||||
|
|
||||||
|
def cache_path
|
||||||
|
MusicBrainz.config.cache_path
|
||||||
|
end
|
||||||
|
|
||||||
|
def cache_path=(value)
|
||||||
|
MusicBrainz.config.cache_path = value
|
||||||
|
end
|
||||||
|
|
||||||
|
module Tools
|
||||||
|
module Proxy
|
||||||
|
def query_interval
|
||||||
|
MusicBrainz.config.query_interval
|
||||||
|
end
|
||||||
|
|
||||||
|
def query_interval=(value)
|
||||||
|
MusicBrainz.config.query_interval = value
|
||||||
|
end
|
||||||
|
|
||||||
|
extend self
|
||||||
|
end
|
||||||
|
|
||||||
|
module Cache
|
||||||
|
def cache_path
|
||||||
|
MusicBrainz.config.cache_path
|
||||||
|
end
|
||||||
|
|
||||||
|
def cache_path=(value)
|
||||||
|
MusicBrainz.config.cache_path = value
|
||||||
|
end
|
||||||
|
|
||||||
|
extend self
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
extend self
|
||||||
|
end
|
10
lib/musicbrainz/middleware.rb
Normal file
10
lib/musicbrainz/middleware.rb
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
module MusicBrainz
|
||||||
|
class Middleware < Faraday::Middleware
|
||||||
|
def call(env)
|
||||||
|
env[:request_headers]["User-Agent"] = MusicBrainz.config.user_agent_string
|
||||||
|
env[:request_headers]["Via"] = "gem musicbrainz/#{VERSION} (#{GH_PAGE_URL})"
|
||||||
|
|
||||||
|
@app.call(env)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
51
lib/musicbrainz/models/artist.rb
Normal file
51
lib/musicbrainz/models/artist.rb
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
module MusicBrainz
|
||||||
|
class Artist
|
||||||
|
include BaseModel
|
||||||
|
|
||||||
|
field :id, String
|
||||||
|
field :type, String
|
||||||
|
field :name, String
|
||||||
|
field :country, String
|
||||||
|
field :date_begin, Time
|
||||||
|
field :date_end, Time
|
||||||
|
field :urls, Hash
|
||||||
|
|
||||||
|
attr_writer :release_groups
|
||||||
|
|
||||||
|
def release_groups
|
||||||
|
@release_groups ||= Client::load(:release_group, { artist: id }, {
|
||||||
|
binding: MusicBrainz::Bindings::ArtistReleaseGroups,
|
||||||
|
create_models: MusicBrainz::ReleaseGroup,
|
||||||
|
sort: :first_release_date
|
||||||
|
}) unless @id.nil?
|
||||||
|
end
|
||||||
|
|
||||||
|
class << self
|
||||||
|
def find(id)
|
||||||
|
Client.load(:artist, { id: id, inc: [:url_rels] }, {
|
||||||
|
binding: MusicBrainz::Bindings::Artist,
|
||||||
|
create_model: MusicBrainz::Artist
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
def search(name)
|
||||||
|
name = CGI.escape(name).gsub(/\!/, '\!')
|
||||||
|
|
||||||
|
Client.load(:artist, { query: "artist:#{name}", limit: 10 }, {
|
||||||
|
binding: MusicBrainz::Bindings::ArtistSearch
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
def discography(mbid)
|
||||||
|
artist = find(mbid)
|
||||||
|
artist.release_groups.each { |rg| rg.releases.each { |r| r.tracks } }
|
||||||
|
artist
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_by_name(name)
|
||||||
|
matches = search(name)
|
||||||
|
matches.empty? ? nil : find(matches.first[:id])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
43
lib/musicbrainz/models/base_model.rb
Normal file
43
lib/musicbrainz/models/base_model.rb
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
module MusicBrainz
|
||||||
|
module BaseModel
|
||||||
|
def self.included(klass)
|
||||||
|
klass.send(:include, InstanceMethods)
|
||||||
|
klass.send(:extend, ClassMethods)
|
||||||
|
end
|
||||||
|
|
||||||
|
module ClassMethods
|
||||||
|
def field(name, type)
|
||||||
|
self.class_exec do
|
||||||
|
attr_reader name
|
||||||
|
|
||||||
|
define_method("#{name}=") do |val|
|
||||||
|
instance_variable_set("@#{name}", validate_type(val, type))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module InstanceMethods
|
||||||
|
def validate_type(val, type)
|
||||||
|
if type == Integer
|
||||||
|
val.to_i
|
||||||
|
elsif type == Float
|
||||||
|
val.to_f
|
||||||
|
elsif type == String
|
||||||
|
val.to_s
|
||||||
|
elsif type == Time
|
||||||
|
if val.nil? or val == ""
|
||||||
|
val = "2030-12-31"
|
||||||
|
elsif val.split("-").length == 1
|
||||||
|
val << "-12-31"
|
||||||
|
elsif val.split("-").length == 2
|
||||||
|
val << "-31"
|
||||||
|
end
|
||||||
|
Time.utc(*val.split("-"))
|
||||||
|
else
|
||||||
|
val
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
31
lib/musicbrainz/models/release.rb
Normal file
31
lib/musicbrainz/models/release.rb
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
module MusicBrainz
|
||||||
|
class Release
|
||||||
|
include BaseModel
|
||||||
|
|
||||||
|
field :id, String
|
||||||
|
field :title, String
|
||||||
|
field :status, String
|
||||||
|
field :format, String
|
||||||
|
field :date, Time
|
||||||
|
field :country, String
|
||||||
|
|
||||||
|
attr_writer :tracks
|
||||||
|
|
||||||
|
def tracks
|
||||||
|
@tracks ||= Client::load(:release, { id: id, inc: [:recordings, :media], limit: 100 }, {
|
||||||
|
binding: MusicBrainz::Bindings::ReleaseTracks,
|
||||||
|
create_models: MusicBrainz::Track,
|
||||||
|
sort: :position
|
||||||
|
}) unless @id.nil?
|
||||||
|
end
|
||||||
|
|
||||||
|
class << self
|
||||||
|
def find(id)
|
||||||
|
Client.load(:release, { id: id, inc: [:media] }, {
|
||||||
|
binding: MusicBrainz::Bindings::Release,
|
||||||
|
create_model: MusicBrainz::Release
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
31
lib/musicbrainz/models/release_group.rb
Normal file
31
lib/musicbrainz/models/release_group.rb
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
module MusicBrainz
|
||||||
|
class ReleaseGroup
|
||||||
|
include BaseModel
|
||||||
|
|
||||||
|
field :id, String
|
||||||
|
field :type, String
|
||||||
|
field :title, String
|
||||||
|
field :desc, String
|
||||||
|
field :first_release_date, Time
|
||||||
|
|
||||||
|
alias_method :disambiguation, :desc
|
||||||
|
attr_writer :releases
|
||||||
|
|
||||||
|
def releases
|
||||||
|
@releases ||= Client::load(:release, { release_group: id, inc: [:media], limit: 100 }, {
|
||||||
|
binding: MusicBrainz::Bindings::ReleaseGroupReleases,
|
||||||
|
create_models: MusicBrainz::Release,
|
||||||
|
sort: :date
|
||||||
|
}) unless @id.nil?
|
||||||
|
end
|
||||||
|
|
||||||
|
class << self
|
||||||
|
def find(id)
|
||||||
|
Client.load(:release_group, { id: id }, {
|
||||||
|
binding: MusicBrainz::Bindings::ReleaseGroup,
|
||||||
|
create_model: MusicBrainz::ReleaseGroup
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
19
lib/musicbrainz/models/track.rb
Normal file
19
lib/musicbrainz/models/track.rb
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
module MusicBrainz
|
||||||
|
class Track
|
||||||
|
include BaseModel
|
||||||
|
|
||||||
|
field :position, Integer
|
||||||
|
field :recording_id, String
|
||||||
|
field :title, String
|
||||||
|
field :length, Integer
|
||||||
|
|
||||||
|
class << self
|
||||||
|
def find(id)
|
||||||
|
Client.load(:recording, { id: id }, {
|
||||||
|
binding: MusicBrainz::Bindings::Track,
|
||||||
|
create_model: MusicBrainz::Track
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -1,43 +0,0 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
|
||||||
|
|
||||||
module MusicBrainz
|
|
||||||
class Release < Base
|
|
||||||
|
|
||||||
field :id, String
|
|
||||||
field :title, String
|
|
||||||
field :status, String
|
|
||||||
field :format, String
|
|
||||||
field :date, Time
|
|
||||||
field :country, String
|
|
||||||
|
|
||||||
def tracks
|
|
||||||
@tracks ||= nil
|
|
||||||
if @tracks.nil? and !id.nil?
|
|
||||||
@tracks = self.class.load({
|
|
||||||
:parser => :release_tracks,
|
|
||||||
:create_models => MusicBrainz::Track
|
|
||||||
}, {
|
|
||||||
:resource => :release,
|
|
||||||
:id => id,
|
|
||||||
:inc => [:recordings, :media],
|
|
||||||
:limit => 100
|
|
||||||
})
|
|
||||||
@tracks.sort{ |a, b| a.position <=> b.position }
|
|
||||||
end
|
|
||||||
@tracks
|
|
||||||
end
|
|
||||||
|
|
||||||
class << self
|
|
||||||
def find(mbid)
|
|
||||||
load({
|
|
||||||
:parser => :release_model,
|
|
||||||
:create_model => MusicBrainz::Release
|
|
||||||
}, {
|
|
||||||
:resource => :release,
|
|
||||||
:id => mbid,
|
|
||||||
:inc => [:media]
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,41 +0,0 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
|
||||||
|
|
||||||
module MusicBrainz
|
|
||||||
class ReleaseGroup < Base
|
|
||||||
|
|
||||||
field :id, String
|
|
||||||
field :type, String
|
|
||||||
field :title, String
|
|
||||||
field :disambiguation, String
|
|
||||||
field :first_release_date, Time
|
|
||||||
|
|
||||||
def releases
|
|
||||||
@releases ||= nil
|
|
||||||
if @releases.nil? and !id.nil?
|
|
||||||
@releases = self.class.load({
|
|
||||||
:parser => :release_group_releases,
|
|
||||||
:create_models => MusicBrainz::Release
|
|
||||||
}, {
|
|
||||||
:resource => :release,
|
|
||||||
:release_group => self.id,
|
|
||||||
:inc => [:media],
|
|
||||||
:limit => 100
|
|
||||||
})
|
|
||||||
@releases.sort!{ |a, b| a.date <=> b.date }
|
|
||||||
end
|
|
||||||
@releases
|
|
||||||
end
|
|
||||||
|
|
||||||
class << self
|
|
||||||
def find(mbid)
|
|
||||||
load({
|
|
||||||
:parser => :release_group_model,
|
|
||||||
:create_model => MusicBrainz::ReleaseGroup
|
|
||||||
}, {
|
|
||||||
:resource => :release_group,
|
|
||||||
:id => mbid
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,23 +0,0 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
|
||||||
|
|
||||||
module MusicBrainz
|
|
||||||
class Track < Base
|
|
||||||
|
|
||||||
field :position, Integer
|
|
||||||
field :recording_id, String
|
|
||||||
field :title, String
|
|
||||||
field :length, Integer
|
|
||||||
|
|
||||||
class << self
|
|
||||||
def find(mbid)
|
|
||||||
load({
|
|
||||||
:parser => :track_model,
|
|
||||||
:create_model => MusicBrainz::Track
|
|
||||||
}, {
|
|
||||||
:resource => :recording,
|
|
||||||
:id => mbid
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
3
lib/musicbrainz/version.rb
Normal file
3
lib/musicbrainz/version.rb
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
module MusicBrainz
|
||||||
|
VERSION = "0.8"
|
||||||
|
end
|
@ -1,47 +0,0 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
|
||||||
|
|
||||||
module MusicBrainz
|
|
||||||
module Parsers
|
|
||||||
class Artist < Base
|
|
||||||
class << self
|
|
||||||
def model(xml)
|
|
||||||
res = {
|
|
||||||
:id => safe_get_attr(xml, "artist", "id"),
|
|
||||||
:type => safe_get_attr(xml, "artist", "type"),
|
|
||||||
:name => safe_get_value(xml, "artist > name").gsub(/[`’]/, "'"),
|
|
||||||
:country => safe_get_value(xml, "artist > country"),
|
|
||||||
:date_begin => safe_get_value(xml, "artist > life-span > begin"),
|
|
||||||
:date_end => safe_get_value(xml, "artist > life-span > end"),
|
|
||||||
:urls => {}
|
|
||||||
}
|
|
||||||
xml.css("relation-list[target-type='url'] > relation").each { |rel|
|
|
||||||
res[:urls][rel.attr("type").downcase.split(" ").join("_").to_sym] = rel.css("target").text
|
|
||||||
}
|
|
||||||
res
|
|
||||||
end
|
|
||||||
|
|
||||||
def search(xml)
|
|
||||||
xml.css("artist-list > artist").map do |a|
|
|
||||||
{
|
|
||||||
:name => a.first_element_child.text.gsub(/[`’]/, "'"),
|
|
||||||
:sort_name => safe_get_value(a, "sort-name").gsub(/[`’]/, "'"),
|
|
||||||
:score => (safe_get_attr(a, nil, "score").to_i rescue 0),
|
|
||||||
:desc => safe_get_value(a, "disambiguation"),
|
|
||||||
:type => safe_get_attr(a, nil, "type"),
|
|
||||||
:mbid => safe_get_attr(a, nil, "id"),
|
|
||||||
:aliases => a.css("alias-list > alias").map { |item| item.text }
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def release_groups(xml)
|
|
||||||
release_groups = []
|
|
||||||
xml.css("release-group").each do |rg|
|
|
||||||
release_groups << MusicBrainz::Parsers::ReleaseGroup.model(rg)
|
|
||||||
end
|
|
||||||
release_groups
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,41 +0,0 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
|
||||||
|
|
||||||
module MusicBrainz
|
|
||||||
module Parsers
|
|
||||||
class << self
|
|
||||||
def get_by_name(name)
|
|
||||||
case name
|
|
||||||
when :artist_model
|
|
||||||
{ :const => MusicBrainz::Parsers::Artist, :method => :model }
|
|
||||||
when :artist_search
|
|
||||||
{ :const => MusicBrainz::Parsers::Artist, :method => :search }
|
|
||||||
when :artist_release_groups
|
|
||||||
{ :const => MusicBrainz::Parsers::Artist, :method => :release_groups }
|
|
||||||
when :release_group_model
|
|
||||||
{ :const => MusicBrainz::Parsers::ReleaseGroup, :method => :model }
|
|
||||||
when :release_group_releases
|
|
||||||
{ :const => MusicBrainz::Parsers::ReleaseGroup, :method => :releases }
|
|
||||||
when :release_model
|
|
||||||
{ :const => MusicBrainz::Parsers::Release, :method => :model }
|
|
||||||
when :release_tracks
|
|
||||||
{ :const => MusicBrainz::Parsers::Release, :method => :tracks }
|
|
||||||
when :track_model
|
|
||||||
{ :const => MusicBrainz::Parsers::Track, :method => :model }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class Base
|
|
||||||
class << self
|
|
||||||
def safe_get_attr(xml, path, name)
|
|
||||||
node = path.nil? ? xml : (xml.css(path).first unless xml.css(path).empty?)
|
|
||||||
node.attr(name) unless node.nil? or node.attr(name).nil?
|
|
||||||
end
|
|
||||||
|
|
||||||
def safe_get_value(xml, path)
|
|
||||||
xml.css(path).first.text unless xml.css(path).empty?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,28 +0,0 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
|
||||||
|
|
||||||
module MusicBrainz
|
|
||||||
module Parsers
|
|
||||||
class Release < Base
|
|
||||||
class << self
|
|
||||||
def model(xml)
|
|
||||||
{
|
|
||||||
:id => safe_get_attr(xml, nil, "id") || safe_get_attr(xml, "release", "id"),
|
|
||||||
:title => safe_get_value(xml, "title"),
|
|
||||||
:status => safe_get_value(xml, "status"),
|
|
||||||
:country => safe_get_value(xml, "country"),
|
|
||||||
:format => safe_get_value(xml, "medium-list > medium > format"),
|
|
||||||
:date => safe_get_value(xml, "date")
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def tracks(xml)
|
|
||||||
tracks = []
|
|
||||||
xml.css("medium-list > medium > track-list > track").each do |r|
|
|
||||||
tracks << MusicBrainz::Parsers::Track.model(r)
|
|
||||||
end
|
|
||||||
tracks
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,27 +0,0 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
|
||||||
|
|
||||||
module MusicBrainz
|
|
||||||
module Parsers
|
|
||||||
class ReleaseGroup < Base
|
|
||||||
class << self
|
|
||||||
def model(xml)
|
|
||||||
{
|
|
||||||
:id => safe_get_attr(xml, nil, "id") || safe_get_attr(xml, "release-group", "id"),
|
|
||||||
:type => safe_get_attr(xml, nil, "type") || safe_get_attr(xml, "release-group", "type"),
|
|
||||||
:title => safe_get_value(xml, "title"),
|
|
||||||
:disambiguation => safe_get_value(xml, "disambiguation"),
|
|
||||||
:first_release_date => safe_get_value(xml, "first-release-date")
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def releases(xml)
|
|
||||||
releases = []
|
|
||||||
xml.css("release").each do |r|
|
|
||||||
releases << MusicBrainz::Parsers::Release.model(r)
|
|
||||||
end
|
|
||||||
releases
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,18 +0,0 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
|
||||||
|
|
||||||
module MusicBrainz
|
|
||||||
module Parsers
|
|
||||||
class Track < Base
|
|
||||||
class << self
|
|
||||||
def model(xml)
|
|
||||||
{
|
|
||||||
:position => safe_get_value(xml, "position"),
|
|
||||||
:recording_id => safe_get_attr(xml, "recording", "id"),
|
|
||||||
:title => safe_get_value(xml, "recording > title"),
|
|
||||||
:length => safe_get_value(xml, "length") || safe_get_value(xml, "recording > length")
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,48 +0,0 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
|
||||||
|
|
||||||
module MusicBrainz
|
|
||||||
module Tools
|
|
||||||
class Cache
|
|
||||||
class << self
|
|
||||||
@@cache_path = nil
|
|
||||||
|
|
||||||
def cache_path=(path)
|
|
||||||
@@cache_path = path
|
|
||||||
end
|
|
||||||
|
|
||||||
def cache_path
|
|
||||||
@@cache_path
|
|
||||||
end
|
|
||||||
|
|
||||||
def clear_cache
|
|
||||||
FileUtils.rm_r(@@cache_path) if @@cache_path && File.exist?(@@cache_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def cache_contents(url)
|
|
||||||
response = nil
|
|
||||||
url_parts = url.split('/')
|
|
||||||
file_name = url_parts.pop
|
|
||||||
directory = url_parts.pop
|
|
||||||
file_path = @@cache_path ? "#{@@cache_path}/#{directory}/#{file_name}" : nil
|
|
||||||
|
|
||||||
if file_path && File.exist?(file_path)
|
|
||||||
response = File.open(file_path).gets
|
|
||||||
else
|
|
||||||
response = yield
|
|
||||||
|
|
||||||
unless response.nil? or file_path.nil?
|
|
||||||
FileUtils.mkdir_p file_path.split('/')[0..-2].join('/')
|
|
||||||
file = File.new(file_path, 'w')
|
|
||||||
file.puts(response.gets) # .force_encoding('UTF-8')
|
|
||||||
file.chmod(0755)
|
|
||||||
file.close
|
|
||||||
response.rewind
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
response
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,54 +0,0 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
|
||||||
|
|
||||||
module MusicBrainz
|
|
||||||
|
|
||||||
def self.configure
|
|
||||||
yield @config ||= MusicBrainz::Tools::Configuration.new
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.config
|
|
||||||
@config
|
|
||||||
end
|
|
||||||
|
|
||||||
module Tools
|
|
||||||
class Configuration
|
|
||||||
def self.add_config name, value=nil
|
|
||||||
self.instance_variable_set "@#{name}", value
|
|
||||||
|
|
||||||
class_eval <<-RUBY
|
|
||||||
def #{name}=(value)
|
|
||||||
@#{name} = value
|
|
||||||
end
|
|
||||||
|
|
||||||
def #{name}
|
|
||||||
@#{name} || self.class.instance_variable_get('@#{name}')
|
|
||||||
end
|
|
||||||
RUBY
|
|
||||||
end
|
|
||||||
|
|
||||||
DEFAULT_USER_AGENT = "gem musicbrainz (https://github.com/magnolia-fan/musicbrainz) @ " + Socket.gethostname
|
|
||||||
|
|
||||||
add_config :application
|
|
||||||
add_config :version
|
|
||||||
add_config :contact
|
|
||||||
|
|
||||||
add_config :query_interval, 1.5
|
|
||||||
add_config :tries_limit, 5
|
|
||||||
|
|
||||||
add_config :web_service_url, "http://musicbrainz.org/ws/2/"
|
|
||||||
|
|
||||||
def user_agent
|
|
||||||
return @user_agent if @user_agent
|
|
||||||
|
|
||||||
if application
|
|
||||||
@user_agent = application
|
|
||||||
@user_agent << "/#{version}" if version
|
|
||||||
@user_agent << " (#{contact})" if contact
|
|
||||||
@user_agent << ' via '
|
|
||||||
end
|
|
||||||
|
|
||||||
@user_agent = "#{@user_agent}#{DEFAULT_USER_AGENT}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,57 +0,0 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
|
||||||
|
|
||||||
module MusicBrainz
|
|
||||||
module Tools
|
|
||||||
class Proxy
|
|
||||||
class << self
|
|
||||||
@@last_query_time = 0
|
|
||||||
|
|
||||||
def config
|
|
||||||
MusicBrainz.config
|
|
||||||
end
|
|
||||||
|
|
||||||
def query_interval=(sec)
|
|
||||||
config.query_interval = sec.to_f
|
|
||||||
end
|
|
||||||
|
|
||||||
def tries_limit=(num)
|
|
||||||
config.tries_limit = num.to_i
|
|
||||||
end
|
|
||||||
|
|
||||||
def query(params = {})
|
|
||||||
url = config.web_service_url + params[:resource].to_s.gsub('_', '-') + '/' + (params[:id].to_s || '')
|
|
||||||
params.delete(:resource)
|
|
||||||
params.delete(:id) unless params[:id].nil?
|
|
||||||
url << '?' + params.map{ |k, v|
|
|
||||||
k = k.to_s.gsub('_', '-')
|
|
||||||
v = (v.is_a?(Array) ? v.map{ |_| _.to_s.gsub('_', '-') }.join('+') : v.to_s)
|
|
||||||
k + '=' + v
|
|
||||||
}.join('&') unless params.empty?
|
|
||||||
MusicBrainz::Tools::Cache.cache_contents(url) {
|
|
||||||
get_contents url
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_contents(url)
|
|
||||||
response = nil
|
|
||||||
|
|
||||||
config.tries_limit.times {
|
|
||||||
time_passed = Time.now.to_f - @@last_query_time
|
|
||||||
sleep(config.query_interval - time_passed) if time_passed < config.query_interval
|
|
||||||
|
|
||||||
begin
|
|
||||||
response = open(url, "User-Agent" => config.user_agent)
|
|
||||||
@@last_query_time = Time.now.to_f
|
|
||||||
rescue => e
|
|
||||||
response = nil if e.io.status[0].to_i == 404
|
|
||||||
end
|
|
||||||
|
|
||||||
break unless response.nil?
|
|
||||||
}
|
|
||||||
|
|
||||||
response
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,5 +0,0 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
|
||||||
|
|
||||||
module MusicBrainz
|
|
||||||
VERSION = "0.7.1"
|
|
||||||
end
|
|
@ -1,6 +1,4 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
require File.expand_path('../lib/musicbrainz/version', __FILE__)
|
||||||
|
|
||||||
require File.expand_path('../lib/version', __FILE__)
|
|
||||||
|
|
||||||
Gem::Specification.new do |gem|
|
Gem::Specification.new do |gem|
|
||||||
gem.authors = ["Gregory Eremin"]
|
gem.authors = ["Gregory Eremin"]
|
||||||
@ -8,16 +6,16 @@ Gem::Specification.new do |gem|
|
|||||||
gem.summary = %q{MusicBrainz Web Service wrapper with ActiveRecord-style models}
|
gem.summary = %q{MusicBrainz Web Service wrapper with ActiveRecord-style models}
|
||||||
gem.homepage = "http://github.com/magnolia-fan/musicbrainz"
|
gem.homepage = "http://github.com/magnolia-fan/musicbrainz"
|
||||||
|
|
||||||
gem.files = `git ls-files`.split($\)
|
gem.files = %x{ git ls-files }.split($\)
|
||||||
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
||||||
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
||||||
gem.name = "musicbrainz"
|
gem.name = "musicbrainz"
|
||||||
gem.require_paths = ["lib"]
|
gem.require_paths = %w[ lib ]
|
||||||
gem.version = MusicBrainz::VERSION
|
gem.version = MusicBrainz::VERSION
|
||||||
gem.license = "MIT"
|
gem.license = "MIT"
|
||||||
|
|
||||||
|
gem.add_dependency("faraday")
|
||||||
gem.add_dependency("nokogiri")
|
gem.add_dependency("nokogiri")
|
||||||
gem.add_development_dependency("rake")
|
|
||||||
gem.add_development_dependency("awesome_print")
|
|
||||||
gem.add_development_dependency("rspec")
|
gem.add_development_dependency("rspec")
|
||||||
|
gem.add_development_dependency("awesome_print")
|
||||||
end
|
end
|
||||||
|
@ -4,35 +4,47 @@ require "spec_helper"
|
|||||||
|
|
||||||
describe MusicBrainz do
|
describe MusicBrainz do
|
||||||
before(:all) {
|
before(:all) {
|
||||||
@old_cache_path = MusicBrainz::Tools::Cache.cache_path
|
@old_cache_path = MusicBrainz.config.cache_path
|
||||||
|
@old_query_interval = MusicBrainz.config.query_interval
|
||||||
}
|
}
|
||||||
|
|
||||||
before(:each) {
|
before(:each) {
|
||||||
$stdout.stub!(:puts)
|
MusicBrainz.config.cache_path = nil
|
||||||
MusicBrainz::Tools::Cache.cache_path = nil
|
MusicBrainz.config.query_interval = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
after(:all) {
|
after(:all) {
|
||||||
MusicBrainz::Tools::Cache.cache_path = @old_cache_path
|
MusicBrainz.config.cache_path = @old_cache_path
|
||||||
|
MusicBrainz.config.query_interval = @old_query_interval
|
||||||
}
|
}
|
||||||
|
|
||||||
it "allows deprecated use of cache_path" do
|
it "allows deprecated use of cache_path" do
|
||||||
MusicBrainz::Tools::Cache.cache_path = "some/path"
|
MusicBrainz.config.cache_path = "test1"
|
||||||
MusicBrainz::cache_path.should == "some/path"
|
|
||||||
|
MusicBrainz::Tools::Cache.cache_path.should == "test1"
|
||||||
|
MusicBrainz.cache_path.should == "test1"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "allows deprecated use of cache_path=" do
|
it "allows deprecated use of cache_path=" do
|
||||||
MusicBrainz.cache_path = "some/path"
|
MusicBrainz::Tools::Cache.cache_path = "test2"
|
||||||
MusicBrainz::Tools::Cache.cache_path.should == "some/path"
|
MusicBrainz.config.cache_path.should == "test2"
|
||||||
|
|
||||||
|
MusicBrainz.cache_path = "test3"
|
||||||
|
MusicBrainz.config.cache_path.should == "test3"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "allows deprecated use of query_interval" do
|
it "allows deprecated use of query_interval" do
|
||||||
MusicBrainz::Tools::Proxy.query_interval = 2
|
MusicBrainz.config.query_interval = 2
|
||||||
MusicBrainz::query_interval.should == 2
|
|
||||||
|
MusicBrainz::Tools::Proxy.query_interval.should == 2
|
||||||
|
MusicBrainz.query_interval.should == 2
|
||||||
end
|
end
|
||||||
|
|
||||||
it "allows deprecated use of query_interval=" do
|
it "allows deprecated use of query_interval=" do
|
||||||
MusicBrainz.query_interval = 2
|
MusicBrainz::Tools::Proxy.query_interval = 3
|
||||||
MusicBrainz::Tools::Proxy.query_interval.should == 2
|
MusicBrainz.config.query_interval.should == 3
|
||||||
|
|
||||||
|
MusicBrainz.query_interval = 4
|
||||||
|
MusicBrainz.config.query_interval.should == 4
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -24,15 +24,9 @@ describe MusicBrainz::Artist do
|
|||||||
matches = MusicBrainz::Artist.search('Chris Martin')
|
matches = MusicBrainz::Artist.search('Chris Martin')
|
||||||
|
|
||||||
matches[0][:score].should == 100
|
matches[0][:score].should == 100
|
||||||
matches[0][:mbid].should == "98d1ec5a-dd97-4c0b-9c83-7928aac89bca"
|
matches[0][:id].should == "98d1ec5a-dd97-4c0b-9c83-7928aac89bca"
|
||||||
matches[1][:score].should == 100
|
matches[1][:score].should == 100
|
||||||
matches[1][:mbid].should == "af2ab893-3212-4226-9e73-73a1660b6952"
|
matches[1][:id].should == "af2ab893-3212-4226-9e73-73a1660b6952"
|
||||||
matches[2][:score].should == 95
|
|
||||||
matches[2][:mbid].should == "444d1b63-534b-4ea6-89f0-0af6ab2e20c3"
|
|
||||||
matches[3][:score].should == 95
|
|
||||||
matches[3][:mbid].should == "b732a912-af95-472c-be52-b14610734c64"
|
|
||||||
matches[4][:score].should == 95
|
|
||||||
matches[4][:mbid].should == "90fff570-a4ef-4cd4-ba21-e00c7261b05a"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "finds name first than alias" do
|
it "finds name first than alias" do
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
|
||||||
|
|
||||||
require "rubygems"
|
require "rubygems"
|
||||||
require "bundler/setup"
|
require "bundler/setup"
|
||||||
require "ap"
|
|
||||||
|
|
||||||
require "musicbrainz"
|
require "musicbrainz"
|
||||||
|
|
||||||
MusicBrainz::Tools::Cache.cache_path = "tmp/cache"
|
MusicBrainz.configure do |c|
|
||||||
|
test_email = %x{ git config --global --get user.email }.gsub(/\n/, "")
|
||||||
|
test_email = "magnolia_fan@me.com" if test_email.empty?
|
||||||
|
|
||||||
|
c.app_name = "MusicBrainzGemTestSuite"
|
||||||
|
c.app_version = MusicBrainz::VERSION
|
||||||
|
c.contact = test_email
|
||||||
|
c.perform_caching = true
|
||||||
|
end
|
||||||
|
|
||||||
RSpec.configure do |config|
|
RSpec.configure do |config|
|
||||||
# Configuration is not currently necessary
|
# Configuration is not currently necessary
|
||||||
|
@ -1,59 +1,64 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
# -*- encoding: utf-8 -*-
|
||||||
|
|
||||||
|
require "ostruct"
|
||||||
require "spec_helper"
|
require "spec_helper"
|
||||||
|
|
||||||
describe MusicBrainz::Tools::Cache do
|
describe MusicBrainz::Tools::Cache do
|
||||||
before(:all) do
|
before(:all) do
|
||||||
@old_cache_path = MusicBrainz::Tools::Cache.cache_path
|
@old_cache_path = MusicBrainz::Tools::Cache.cache_path
|
||||||
@tmp_cache_path = File.join(File.dirname(__FILE__), '../../tmp/cache/tools')
|
@tmp_cache_path = File.join(File.dirname(__FILE__), "../../tmp/cache/test")
|
||||||
|
@test_mbid = "69b39eab-6577-46a4-a9f5-817839092033"
|
||||||
|
@test_cache_file = "#{@tmp_cache_path}/03/48/ec6c2bee685d9a96f95ed46378f624714e7a4650b0d44c1a8eee5bac2480.xml"
|
||||||
end
|
end
|
||||||
|
|
||||||
after(:all) do
|
after(:all) do
|
||||||
MusicBrainz::Tools::Cache.cache_path = @old_cache_path
|
MusicBrainz.config.cache_path = @old_cache_path
|
||||||
end
|
end
|
||||||
|
|
||||||
before(:each) do
|
before(:each) do
|
||||||
file_path = File.join(File.dirname(__FILE__), "../fixtures/kasabian.xml")
|
file_path = File.join(File.dirname(__FILE__), "../fixtures/kasabian.xml")
|
||||||
@test_response = ::StringIO.new(File.open(file_path).gets)
|
@test_response = File.open(file_path).read
|
||||||
end
|
end
|
||||||
|
|
||||||
context "with cache enabled" do
|
context "with cache enabled" do
|
||||||
it "calls get contents only once when requesting the resource twice" do
|
it "calls http only once when requesting the resource twice" do
|
||||||
MusicBrainz::Tools::Cache.cache_path = @tmp_cache_path
|
MusicBrainz.config.cache_path = @tmp_cache_path
|
||||||
mbid = "69b39eab-6577-46a4-a9f5-817839092033"
|
File.exist?(@test_cache_file).should be_false
|
||||||
|
|
||||||
MusicBrainz::Tools::Proxy.stub(:get_contents).and_return(@test_response)
|
# Stubbing
|
||||||
MusicBrainz::Tools::Proxy.should_receive(:get_contents).once
|
MusicBrainz::Client.http.stub(:get).and_return(OpenStruct.new(status: 200, body: @test_response))
|
||||||
|
MusicBrainz::Client.http.should_receive(:get).once
|
||||||
|
|
||||||
File.exist?("#{@tmp_cache_path}/artist/#{mbid}?inc=url-rels").should be_false
|
2.times do
|
||||||
artist = MusicBrainz::Artist.find(mbid)
|
artist = MusicBrainz::Artist.find(@test_mbid)
|
||||||
artist.should be_a_kind_of(MusicBrainz::Artist)
|
artist.should be_a_kind_of(MusicBrainz::Artist)
|
||||||
|
File.exist?(@test_cache_file).should be_true
|
||||||
|
end
|
||||||
|
|
||||||
File.exist?("#{@tmp_cache_path}/artist/#{mbid}?inc=url-rels").should be_true
|
MusicBrainz::Client.clear_cache
|
||||||
artist = MusicBrainz::Artist.find(mbid)
|
|
||||||
artist.should be_a_kind_of(MusicBrainz::Artist)
|
|
||||||
|
|
||||||
MusicBrainz::Tools::Cache.clear_cache
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "with cache disabled" do
|
context "with cache disabled" do
|
||||||
it "calls get contents twice when requesting the resource twice" do
|
it "calls http twice when requesting the resource twice" do
|
||||||
MusicBrainz::Tools::Cache.cache_path = nil
|
MusicBrainz.config.perform_caching = false
|
||||||
mbid = "69b39eab-6577-46a4-a9f5-817839092033"
|
File.exist?(@test_cache_file).should be_false
|
||||||
|
|
||||||
MusicBrainz::Tools::Proxy.stub(:get_contents).and_return(@test_response)
|
# Hacking for test performance purposes
|
||||||
MusicBrainz::Tools::Proxy.should_receive(:get_contents).twice
|
MusicBrainz.config.query_interval = 0.0
|
||||||
|
|
||||||
File.exist?("#{@tmp_cache_path}/artist/#{mbid}?inc=url-rels").should be_false
|
# Stubbing
|
||||||
artist = MusicBrainz::Artist.find(mbid)
|
MusicBrainz::Client.http.stub(:get).and_return(OpenStruct.new(status: 200, body: @test_response))
|
||||||
artist.should be_a_kind_of(MusicBrainz::Artist)
|
MusicBrainz::Client.http.should_receive(:get).twice
|
||||||
|
|
||||||
File.exist?("#{@tmp_cache_path}/artist/#{mbid}?inc=url-rels").should be_false
|
2.times do
|
||||||
@test_response.rewind
|
artist = MusicBrainz::Artist.find(@test_mbid)
|
||||||
MusicBrainz.stub(:get_contents).and_return(@test_response)
|
artist.should be_a_kind_of(MusicBrainz::Artist)
|
||||||
artist = MusicBrainz::Artist.find(mbid)
|
File.exist?(@test_cache_file).should be_false
|
||||||
artist.should be_a_kind_of(MusicBrainz::Artist)
|
end
|
||||||
|
|
||||||
|
MusicBrainz.config.perform_caching = true
|
||||||
|
MusicBrainz.config.query_interval = 1.5
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user