musicbrainz 0.7.1 → 0.7.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -4
- data/.travis.yml +2 -2
- data/Contributors +1 -0
- data/README.md +91 -40
- data/lib/mb.rb +2 -0
- data/lib/musicbrainz.rb +27 -22
- data/lib/musicbrainz/bindings/artist.rb +23 -0
- data/lib/musicbrainz/bindings/artist_release_groups.rb +13 -0
- data/lib/musicbrainz/bindings/artist_search.rb +23 -0
- data/lib/musicbrainz/bindings/release.rb +28 -0
- data/lib/musicbrainz/bindings/release_group.rb +18 -0
- data/lib/musicbrainz/bindings/release_group_releases.rb +13 -0
- data/lib/musicbrainz/bindings/release_tracks.rb +13 -0
- data/lib/musicbrainz/bindings/track.rb +16 -0
- data/lib/musicbrainz/client.rb +72 -0
- data/lib/musicbrainz/client_modules/caching_proxy.rb +46 -0
- data/lib/musicbrainz/client_modules/failsafe_proxy.rb +38 -0
- data/lib/musicbrainz/client_modules/transparent_proxy.rb +12 -0
- data/lib/musicbrainz/configuration.rb +60 -0
- data/lib/musicbrainz/deprecated.rb +36 -0
- data/lib/musicbrainz/middleware.rb +23 -0
- data/lib/musicbrainz/models/artist.rb +47 -0
- data/lib/musicbrainz/models/base_model.rb +63 -0
- data/lib/musicbrainz/models/release.rb +27 -0
- data/lib/musicbrainz/models/release_group.rb +28 -0
- data/lib/musicbrainz/models/track.rb +17 -0
- data/lib/musicbrainz/version.rb +3 -0
- data/musicbrainz.gemspec +10 -12
- data/spec/bindings/release_spec.rb +43 -0
- data/spec/client_modules/cache_spec.rb +62 -0
- data/spec/deprecated/cache_config_spec.rb +32 -0
- data/spec/deprecated/proxy_config_spec.rb +32 -0
- data/spec/{requests → models}/artist_spec.rb +3 -9
- data/spec/{requests → models}/release_group_spec.rb +2 -2
- data/spec/{requests → models}/release_spec.rb +1 -1
- data/spec/{requests → models}/track_spec.rb +0 -0
- data/spec/spec_helper.rb +13 -7
- metadata +63 -58
- data/Rakefile +0 -13
- data/lib/deprecated.rb +0 -25
- data/lib/musicbrainz/artist.rb +0 -63
- data/lib/musicbrainz/base.rb +0 -71
- data/lib/musicbrainz/release.rb +0 -43
- data/lib/musicbrainz/release_group.rb +0 -41
- data/lib/musicbrainz/track.rb +0 -23
- data/lib/parsers/artist.rb +0 -47
- data/lib/parsers/base.rb +0 -41
- data/lib/parsers/release.rb +0 -28
- data/lib/parsers/release_group.rb +0 -27
- data/lib/parsers/track.rb +0 -18
- data/lib/tools/cache.rb +0 -48
- data/lib/tools/proxy.rb +0 -62
- data/lib/version.rb +0 -5
- data/spec/misc/deprecated_spec.rb +0 -38
- data/spec/tools/cache_spec.rb +0 -59
@@ -0,0 +1,46 @@
|
|
1
|
+
module MusicBrainz
|
2
|
+
module ClientModules
|
3
|
+
module CachingProxy
|
4
|
+
def cache_path
|
5
|
+
MusicBrainz.config.cache_path
|
6
|
+
end
|
7
|
+
|
8
|
+
def clear_cache
|
9
|
+
FileUtils.rm_r(cache_path) if cache_path && File.exist?(cache_path)
|
10
|
+
end
|
11
|
+
|
12
|
+
def get_contents(url)
|
13
|
+
return super unless caching?
|
14
|
+
|
15
|
+
hash = Digest::SHA256.hexdigest(url)
|
16
|
+
dir_path = [cache_path, *(0..2).map{ |i| hash.slice(2*i, 2) }].join(?/)
|
17
|
+
file_path = [dir_path, '/', hash.slice(6, 58), '.xml'].join
|
18
|
+
|
19
|
+
response = { body: nil, status: 500 }
|
20
|
+
|
21
|
+
if File.exist?(file_path)
|
22
|
+
response = {
|
23
|
+
body: File.open(file_path, 'rb').gets,
|
24
|
+
status: 200
|
25
|
+
}
|
26
|
+
else
|
27
|
+
response = super
|
28
|
+
if response[:status] == 200
|
29
|
+
FileUtils.mkpath(dir_path)
|
30
|
+
File.open(file_path, 'wb') do |f|
|
31
|
+
f.puts(response[:body])
|
32
|
+
f.chmod(0755)
|
33
|
+
f.close
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
response
|
39
|
+
end
|
40
|
+
|
41
|
+
def caching?
|
42
|
+
MusicBrainz.config.perform_caching
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module MusicBrainz
|
2
|
+
module ClientModules
|
3
|
+
module FailsafeProxy
|
4
|
+
def get_contents(url)
|
5
|
+
return super unless failsafe?
|
6
|
+
|
7
|
+
response = { body: nil, status: 500 }
|
8
|
+
MusicBrainz.config.tries_limit.times do
|
9
|
+
response = super
|
10
|
+
break if response[:status] == 200
|
11
|
+
end
|
12
|
+
|
13
|
+
response
|
14
|
+
end
|
15
|
+
|
16
|
+
def time_passed
|
17
|
+
Time.now.to_f - @last_query_time ||= 0.0
|
18
|
+
end
|
19
|
+
|
20
|
+
def time_to_wait
|
21
|
+
MusicBrainz.config.query_interval - time_passed
|
22
|
+
end
|
23
|
+
|
24
|
+
def ready?
|
25
|
+
time_passed > MusicBrainz.config.query_interval
|
26
|
+
end
|
27
|
+
|
28
|
+
def wait_util_ready!
|
29
|
+
sleep(time_to_wait) unless ready?
|
30
|
+
@last_query_time = Time.now.to_f
|
31
|
+
end
|
32
|
+
|
33
|
+
def failsafe?
|
34
|
+
MusicBrainz.config.tries_limit > 1 && MusicBrainz.config.query_interval.to_f > 0
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module MusicBrainz
|
2
|
+
class Configuration
|
3
|
+
attr_accessor :app_name, :app_version, :contact,
|
4
|
+
:web_service_url,
|
5
|
+
:query_interval, :tries_limit,
|
6
|
+
:cache_path, :perform_caching
|
7
|
+
|
8
|
+
DEFAULT_WEB_SERVICE_URL = "http://musicbrainz.org/ws/2/"
|
9
|
+
DEFAULT_QUERY_INTERVAL = 1.5
|
10
|
+
DEFAULT_TRIES_LIMIT = 5
|
11
|
+
DEFAULT_CACHE_PATH = File.join(File.dirname(__FILE__), "..", "tmp", "cache")
|
12
|
+
DEFAULT_PERFORM_CACHING = false
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@web_service_url = DEFAULT_WEB_SERVICE_URL
|
16
|
+
@query_interval = DEFAULT_QUERY_INTERVAL
|
17
|
+
@tries_limit = DEFAULT_TRIES_LIMIT
|
18
|
+
@cache_path = DEFAULT_CACHE_PATH
|
19
|
+
@perform_caching = DEFAULT_PERFORM_CACHING
|
20
|
+
end
|
21
|
+
|
22
|
+
def valid?
|
23
|
+
%w[ app_name app_version contact ].each do |param|
|
24
|
+
unless instance_variable_defined?(:"@#{param}")
|
25
|
+
raise Exception.new("Application identity parameter '#{param}' missing")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
unless tries_limit.nil? && query_interval.nil?
|
29
|
+
raise Exception.new("'tries_limit' parameter must be 1 or greater") if tries_limit.to_i < 1
|
30
|
+
raise Exception.new("'query_interval' parameter must be greater than zero") if query_interval.to_f < 0
|
31
|
+
end
|
32
|
+
if perform_caching
|
33
|
+
raise Exception.new("'cache_path' parameter must be set") if cache_path.nil?
|
34
|
+
end
|
35
|
+
true
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
module Configurable
|
40
|
+
def configure
|
41
|
+
raise Exception.new("Configuration block missing") unless block_given?
|
42
|
+
yield @config ||= MusicBrainz::Configuration.new
|
43
|
+
config.valid?
|
44
|
+
end
|
45
|
+
|
46
|
+
def config
|
47
|
+
raise Exception.new("Configuration missing") unless instance_variable_defined?(:@config)
|
48
|
+
@config
|
49
|
+
end
|
50
|
+
|
51
|
+
def apply_test_configuration!
|
52
|
+
configure do |c|
|
53
|
+
c.app_name = "gem musicbrainz (development mode)"
|
54
|
+
c.app_version = MusicBrainz::VERSION
|
55
|
+
c.contact = `git config user.email`.chomp
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
extend Configurable
|
60
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module MusicBrainz
|
2
|
+
module Deprecated
|
3
|
+
module ProxyConfig
|
4
|
+
def query_interval
|
5
|
+
MusicBrainz.config.query_interval
|
6
|
+
end
|
7
|
+
|
8
|
+
def query_interval=(value)
|
9
|
+
MusicBrainz.config.query_interval = value
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module CacheConfig
|
14
|
+
def cache_path
|
15
|
+
MusicBrainz.config.cache_path
|
16
|
+
end
|
17
|
+
|
18
|
+
def cache_path=(value)
|
19
|
+
MusicBrainz.config.cache_path = value
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
module Tools
|
25
|
+
module Proxy
|
26
|
+
extend Deprecated::ProxyConfig
|
27
|
+
end
|
28
|
+
|
29
|
+
module Cache
|
30
|
+
extend Deprecated::CacheConfig
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
extend Deprecated::ProxyConfig
|
35
|
+
extend Deprecated::CacheConfig
|
36
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module MusicBrainz
|
2
|
+
class Middleware < Faraday::Middleware
|
3
|
+
def call(env)
|
4
|
+
env[:request_headers].merge!(
|
5
|
+
"User-Agent" => user_agent_string,
|
6
|
+
"Via" => via_string
|
7
|
+
)
|
8
|
+
@app.call(env)
|
9
|
+
end
|
10
|
+
|
11
|
+
def user_agent_string
|
12
|
+
"#{config.app_name}/#{config.app_version} ( #{config.contact} )"
|
13
|
+
end
|
14
|
+
|
15
|
+
def via_string
|
16
|
+
"gem musicbrainz/#{VERSION} (#{GH_PAGE_URL})"
|
17
|
+
end
|
18
|
+
|
19
|
+
def config
|
20
|
+
MusicBrainz.config
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module MusicBrainz
|
2
|
+
class Artist < BaseModel
|
3
|
+
field :id, String
|
4
|
+
field :type, String
|
5
|
+
field :name, String
|
6
|
+
field :country, String
|
7
|
+
field :date_begin, Date
|
8
|
+
field :date_end, Date
|
9
|
+
field :urls, Hash
|
10
|
+
|
11
|
+
def release_groups
|
12
|
+
@release_groups ||= client.load(:release_group, { artist: id }, {
|
13
|
+
binding: :artist_release_groups,
|
14
|
+
create_models: :release_group,
|
15
|
+
sort: :first_release_date
|
16
|
+
}) unless @id.nil?
|
17
|
+
end
|
18
|
+
|
19
|
+
class << self
|
20
|
+
def find(id)
|
21
|
+
client.load(:artist, { id: id, inc: [:url_rels] }, {
|
22
|
+
binding: :artist,
|
23
|
+
create_model: :artist
|
24
|
+
})
|
25
|
+
end
|
26
|
+
|
27
|
+
def search(name)
|
28
|
+
name = CGI.escape(name).gsub(/\!/, '\!')
|
29
|
+
|
30
|
+
client.load(:artist, { query: "artist:#{name}", limit: 10 }, {
|
31
|
+
binding: :artist_search
|
32
|
+
})
|
33
|
+
end
|
34
|
+
|
35
|
+
def discography(mbid)
|
36
|
+
artist = find(mbid)
|
37
|
+
artist.release_groups.each { |rg| rg.releases.each { |r| r.tracks } }
|
38
|
+
artist
|
39
|
+
end
|
40
|
+
|
41
|
+
def find_by_name(name)
|
42
|
+
matches = search(name)
|
43
|
+
matches.empty? ? nil : find(matches.first[:id])
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module MusicBrainz
|
2
|
+
class BaseModel
|
3
|
+
def self.inherited(klass)
|
4
|
+
klass.send(:include, InstanceMethods)
|
5
|
+
klass.send(:extend, ClassMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def field(name, type)
|
10
|
+
fields[name] = type
|
11
|
+
attr_reader name
|
12
|
+
|
13
|
+
define_method("#{name}=") do |val|
|
14
|
+
instance_variable_set("@#{name}", validate_type(val, type))
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def fields
|
19
|
+
instance_variable_set(:@fields, {}) unless instance_variable_defined?(:@fields)
|
20
|
+
instance_variable_get(:@fields)
|
21
|
+
end
|
22
|
+
|
23
|
+
def client
|
24
|
+
MusicBrainz.client
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module InstanceMethods
|
29
|
+
def initialize(params = {})
|
30
|
+
params.each do |field, value|
|
31
|
+
self.send(:"#{field}=", value)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def client
|
36
|
+
MusicBrainz.client
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def validate_type(val, type)
|
42
|
+
if type == Integer
|
43
|
+
val.to_i
|
44
|
+
elsif type == Float
|
45
|
+
val.to_f
|
46
|
+
elsif type == String
|
47
|
+
val.to_s
|
48
|
+
elsif type == Date
|
49
|
+
if val.nil? or val == ""
|
50
|
+
val = "2030-12-31"
|
51
|
+
elsif val.split("-").length == 1
|
52
|
+
val << "-12-31"
|
53
|
+
elsif val.split("-").length == 2
|
54
|
+
val << "-31"
|
55
|
+
end
|
56
|
+
Date.new(*val.split(?-).map(&:to_i))
|
57
|
+
else
|
58
|
+
val
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module MusicBrainz
|
2
|
+
class Release < BaseModel
|
3
|
+
field :id, String
|
4
|
+
field :title, String
|
5
|
+
field :status, String
|
6
|
+
field :format, String
|
7
|
+
field :date, Date
|
8
|
+
field :country, String
|
9
|
+
|
10
|
+
def tracks
|
11
|
+
@tracks ||= client.load(:release, { id: id, inc: [:recordings, :media], limit: 100 }, {
|
12
|
+
binding: :release_tracks,
|
13
|
+
create_models: :track,
|
14
|
+
sort: :position
|
15
|
+
}) unless @id.nil?
|
16
|
+
end
|
17
|
+
|
18
|
+
class << self
|
19
|
+
def find(id)
|
20
|
+
client.load(:release, { id: id, inc: [:media] }, {
|
21
|
+
binding: :release,
|
22
|
+
create_model: :release
|
23
|
+
})
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module MusicBrainz
|
2
|
+
class ReleaseGroup < BaseModel
|
3
|
+
field :id, String
|
4
|
+
field :type, String
|
5
|
+
field :title, String
|
6
|
+
field :desc, String
|
7
|
+
field :first_release_date, Date
|
8
|
+
|
9
|
+
alias_method :disambiguation, :desc
|
10
|
+
|
11
|
+
def releases
|
12
|
+
@releases ||= client.load(:release, { release_group: id, inc: [:media], limit: 100 }, {
|
13
|
+
binding: :release_group_releases,
|
14
|
+
create_models: :release,
|
15
|
+
sort: :date
|
16
|
+
}) unless @id.nil?
|
17
|
+
end
|
18
|
+
|
19
|
+
class << self
|
20
|
+
def find(id)
|
21
|
+
client.load(:release_group, { id: id }, {
|
22
|
+
binding: :release_group,
|
23
|
+
create_model: :release_group
|
24
|
+
})
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module MusicBrainz
|
2
|
+
class Track < BaseModel
|
3
|
+
field :position, Integer
|
4
|
+
field :recording_id, String
|
5
|
+
field :title, String
|
6
|
+
field :length, Integer
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def find(id)
|
10
|
+
client.load(:recording, { id: id }, {
|
11
|
+
binding: :track,
|
12
|
+
create_model: :track
|
13
|
+
})
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/musicbrainz.gemspec
CHANGED
@@ -1,23 +1,21 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require File.expand_path('../lib/version', __FILE__)
|
1
|
+
require File.expand_path('../lib/musicbrainz/version', __FILE__)
|
4
2
|
|
5
3
|
Gem::Specification.new do |gem|
|
6
4
|
gem.authors = ["Gregory Eremin"]
|
7
5
|
gem.email = ["magnolia_fan@me.com"]
|
8
|
-
gem.summary = %q{MusicBrainz Web Service wrapper with ActiveRecord-style models}
|
6
|
+
gem.summary = %q{ MusicBrainz Web Service wrapper with ActiveRecord-style models }
|
9
7
|
gem.homepage = "http://github.com/magnolia-fan/musicbrainz"
|
10
8
|
|
11
|
-
gem.files =
|
12
|
-
gem.executables =
|
13
|
-
gem.test_files = gem.files.grep(%r{^
|
9
|
+
gem.files = %x{ git ls-files }.split($\)
|
10
|
+
gem.executables = []
|
11
|
+
gem.test_files = gem.files.grep(%r{^spec/})
|
14
12
|
gem.name = "musicbrainz"
|
15
|
-
gem.require_paths = [
|
13
|
+
gem.require_paths = %w[ lib ]
|
16
14
|
gem.version = MusicBrainz::VERSION
|
17
15
|
gem.license = "MIT"
|
18
16
|
|
19
|
-
gem.add_dependency(
|
20
|
-
gem.
|
21
|
-
gem.add_development_dependency(
|
22
|
-
gem.add_development_dependency(
|
17
|
+
gem.add_dependency('faraday')
|
18
|
+
gem.add_dependency('nokogiri')
|
19
|
+
gem.add_development_dependency('rspec')
|
20
|
+
gem.add_development_dependency('awesome_print')
|
23
21
|
end
|