musicbrainz 0.5.2 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +8 -0
- data/.rspec +1 -0
- data/Gemfile +2 -15
- data/{LICENSE.txt → LICENSE} +4 -2
- data/README.md +86 -0
- data/Rakefile +6 -51
- data/lib/deprecated.rb +12 -0
- data/lib/musicbrainz.rb +15 -6
- data/lib/{models/music_brainz → musicbrainz}/artist.rb +17 -11
- data/lib/{models/music_brainz → musicbrainz}/base.rb +8 -3
- data/lib/{models/music_brainz → musicbrainz}/release.rb +6 -5
- data/lib/{models/music_brainz → musicbrainz}/release_group.rb +6 -5
- data/lib/{models/music_brainz → musicbrainz}/track.rb +4 -3
- data/lib/tools/cache.rb +45 -0
- data/lib/tools/proxy.rb +54 -0
- data/lib/version.rb +4 -0
- data/musicbrainz.gemspec +17 -81
- data/spec/requests/artist_spec.rb +44 -39
- data/spec/requests/release_group_spec.rb +32 -0
- data/spec/requests/release_spec.rb +32 -0
- data/spec/requests/track_spec.rb +21 -0
- data/spec/spec_helper.rb +7 -15
- data/spec/tools/cache_spec.rb +71 -0
- metadata +79 -139
- data/.document +0 -5
- data/README.rdoc +0 -76
- data/VERSION +0 -1
- data/lib/models/music_brainz.rb +0 -38
- data/spec/support/vcr.rb +0 -13
- data/test/helper.rb +0 -18
- data/test/test_musicbrainz_artist.rb +0 -47
- data/test/test_musicbrainz_release.rb +0 -36
- data/test/test_musicbrainz_release_group.rb +0 -36
- data/test/test_musicbrainz_track.rb +0 -25
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
CHANGED
@@ -1,15 +1,2 @@
|
|
1
|
-
source
|
2
|
-
|
3
|
-
group :development do
|
4
|
-
gem "bundler", "~> 1.0.0"
|
5
|
-
gem "jeweler", "~> 1.6.4"
|
6
|
-
gem "rcov", ">= 0"
|
7
|
-
gem "rdoc", ">= 0"
|
8
|
-
gem "shoulda"
|
9
|
-
|
10
|
-
gem "rspec"
|
11
|
-
gem "vcr"
|
12
|
-
gem "webmock"
|
13
|
-
end
|
14
|
-
|
15
|
-
gem "nokogiri", ">= 0"
|
1
|
+
source :rubygems
|
2
|
+
gemspec
|
data/{LICENSE.txt → LICENSE}
RENAMED
@@ -1,4 +1,6 @@
|
|
1
|
-
Copyright (c)
|
1
|
+
Copyright (c) 2012 Gregory Eremin
|
2
|
+
|
3
|
+
MIT License
|
2
4
|
|
3
5
|
Permission is hereby granted, free of charge, to any person obtaining
|
4
6
|
a copy of this software and associated documentation files (the
|
@@ -17,4 +19,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
19
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
20
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
21
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
## MusicBrainz Web Service wrapper [![Travis CI](https://secure.travis-ci.org/magnolia-fan/musicbrainz.png)](http://travis-ci.org/magnolia-fan/musicbrainz)
|
2
|
+
|
3
|
+
### Installation
|
4
|
+
```bash
|
5
|
+
gem install musicbrainz
|
6
|
+
```
|
7
|
+
### Usage
|
8
|
+
```ruby
|
9
|
+
require 'musicbrainz'
|
10
|
+
|
11
|
+
# Search for artists
|
12
|
+
@suggestions = MusicBrainz::Artist.search('Jet')
|
13
|
+
|
14
|
+
# Find artist by name or mbid
|
15
|
+
@foo_fighters = MusicBrainz::Artist.find_by_name('Foo Fighters')
|
16
|
+
@kasabian = MusicBrainz::Artist.find('69b39eab-6577-46a4-a9f5-817839092033')
|
17
|
+
|
18
|
+
# Use them like ActiveRecord models
|
19
|
+
@empire_tracks = @kasabian.release_groups[8].releases.first.tracks
|
20
|
+
|
21
|
+
# Setting a cache path enables caching of requests
|
22
|
+
MusicBrainz::Tools::Cache.cache_path = "tmp/cache"
|
23
|
+
|
24
|
+
# Configuring request interval
|
25
|
+
MusicBrainz::Tools::Proxy.query_interval = 1.2 # seconds
|
26
|
+
```
|
27
|
+
|
28
|
+
### Api
|
29
|
+
|
30
|
+
MusicBrainz::Artist
|
31
|
+
```ruby
|
32
|
+
@artists = MusicBrainz::Artist.search(query)
|
33
|
+
@artist = MusicBrainz::Artist.find_by_name(name)
|
34
|
+
@artist = MusicBrainz::Artist.find(mbid)
|
35
|
+
@artist.id
|
36
|
+
@artist.type
|
37
|
+
@artist.name
|
38
|
+
@artist.country
|
39
|
+
@artist.date_begin
|
40
|
+
@artist.date_end
|
41
|
+
@artist.release_groups
|
42
|
+
```
|
43
|
+
|
44
|
+
MusicBrainz::ReleaseGroup
|
45
|
+
```ruby
|
46
|
+
@release_group = MusicBrainz::ReleaseGroup.find(mbid)
|
47
|
+
@release_group.id
|
48
|
+
@release_group.type
|
49
|
+
@release_group.title
|
50
|
+
@release_group.first_release_date
|
51
|
+
@release_group.releases
|
52
|
+
```
|
53
|
+
|
54
|
+
MusicBrainz::Release
|
55
|
+
```ruby
|
56
|
+
@release = MusicBrainz::Release.find(mbid)
|
57
|
+
@release.id
|
58
|
+
@release.title
|
59
|
+
@release.status
|
60
|
+
@release.date
|
61
|
+
@release.country
|
62
|
+
@release.tracks
|
63
|
+
```
|
64
|
+
|
65
|
+
MusicBrainz::Track
|
66
|
+
```ruby
|
67
|
+
@track = MusicBrainz::Track.find(mbid)
|
68
|
+
@track.position
|
69
|
+
@track.recording_id
|
70
|
+
@track.title
|
71
|
+
@track.length
|
72
|
+
```
|
73
|
+
|
74
|
+
### Contributing
|
75
|
+
|
76
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
77
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
78
|
+
* Fork the project
|
79
|
+
* Start a feature/bugfix branch
|
80
|
+
* Commit and push until you are happy with your contribution
|
81
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
82
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
83
|
+
|
84
|
+
### Copyright
|
85
|
+
|
86
|
+
Copyright (c) 2011 Gregory Eremin. See [LICENSE](https://raw.github.com/magnolia-fan/musicbrainz/master/LICENSE) for further details.
|
data/Rakefile
CHANGED
@@ -1,53 +1,8 @@
|
|
1
|
-
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require "bundler/gem_tasks"
|
3
|
+
require "rspec/core/rake_task"
|
2
4
|
|
3
|
-
|
4
|
-
require 'bundler'
|
5
|
-
begin
|
6
|
-
Bundler.setup(:default, :development)
|
7
|
-
rescue Bundler::BundlerError => e
|
8
|
-
$stderr.puts e.message
|
9
|
-
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
-
exit e.status_code
|
11
|
-
end
|
12
|
-
require 'rake'
|
5
|
+
RSpec::Core::RakeTask.new("spec")
|
13
6
|
|
14
|
-
|
15
|
-
|
16
|
-
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
-
gem.name = "musicbrainz"
|
18
|
-
gem.homepage = "http://github.com/magnolia-fan/musicbrainz"
|
19
|
-
gem.license = "MIT"
|
20
|
-
gem.summary = %Q{MusicBrainz Web Service wrapper}
|
21
|
-
gem.description = %Q{MusicBrainz Web Service wrapper with ActiveRecord-style models}
|
22
|
-
gem.email = "magnolia_fan@me.com"
|
23
|
-
gem.authors = ["Gregory Eremin"]
|
24
|
-
# dependencies defined in Gemfile
|
25
|
-
end
|
26
|
-
Jeweler::RubygemsDotOrgTasks.new
|
27
|
-
|
28
|
-
require 'rake/testtask'
|
29
|
-
Rake::TestTask.new(:test) do |test|
|
30
|
-
test.libs << 'lib' << 'test'
|
31
|
-
test.pattern = 'test/**/test_*.rb'
|
32
|
-
test.verbose = true
|
33
|
-
end
|
34
|
-
|
35
|
-
require 'rcov/rcovtask'
|
36
|
-
Rcov::RcovTask.new do |test|
|
37
|
-
test.libs << 'test'
|
38
|
-
test.pattern = 'test/**/test_*.rb'
|
39
|
-
test.verbose = true
|
40
|
-
test.rcov_opts << '--exclude "gems/*"'
|
41
|
-
end
|
42
|
-
|
43
|
-
task :default => :test
|
44
|
-
|
45
|
-
require 'rdoc/task'
|
46
|
-
RDoc::Task.new do |rdoc|
|
47
|
-
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
48
|
-
|
49
|
-
rdoc.rdoc_dir = 'rdoc'
|
50
|
-
rdoc.title = "musicbrainz #{version}"
|
51
|
-
rdoc.rdoc_files.include('README*')
|
52
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
53
|
-
end
|
7
|
+
task :default => :spec
|
8
|
+
task :test => :spec
|
data/lib/deprecated.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
module MusicBrainz
|
3
|
+
def self.query_interval=(sec)
|
4
|
+
MusicBrainz::Tools::Proxy.query_interval = sec
|
5
|
+
puts "WARNING! MusicBrainz.query_interval is deprecated. Use MusicBrainz::Tools::Proxy.query_interval"
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.cache_path=(path)
|
9
|
+
MusicBrainz::Tools::Cache.cache_path = path
|
10
|
+
puts "WARNING! MusicBrainz.cache_path is deprecated. Use MusicBrainz::Tools::Cache.cache_path"
|
11
|
+
end
|
12
|
+
end
|
data/lib/musicbrainz.rb
CHANGED
@@ -1,11 +1,20 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
1
2
|
require "open-uri"
|
2
3
|
require "socket"
|
3
4
|
require "nokogiri"
|
4
5
|
require "cgi"
|
5
6
|
|
6
|
-
require "
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
require "version"
|
8
|
+
|
9
|
+
module MusicBrainz
|
10
|
+
autoload :Base, "musicbrainz/base"
|
11
|
+
autoload :Artist, "musicbrainz/artist"
|
12
|
+
autoload :ReleaseGroup, "musicbrainz/release_group"
|
13
|
+
autoload :Release, "musicbrainz/release"
|
14
|
+
autoload :Track, "musicbrainz/track"
|
15
|
+
|
16
|
+
module Tools
|
17
|
+
autoload :Cache, "tools/cache"
|
18
|
+
autoload :Proxy, "tools/proxy"
|
19
|
+
end
|
20
|
+
end
|
@@ -1,26 +1,26 @@
|
|
1
|
-
# encoding:
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
2
|
|
3
3
|
module MusicBrainz
|
4
4
|
class Artist < MusicBrainz::Base
|
5
5
|
attr_accessor :id, :type, :name, :country, :date_begin, :date_end, :urls
|
6
6
|
@release_groups
|
7
|
-
|
7
|
+
|
8
8
|
def release_groups
|
9
9
|
if @release_groups.nil? and not self.id.nil?
|
10
10
|
@release_groups = []
|
11
|
-
Nokogiri::XML(
|
11
|
+
Nokogiri::XML(self.class.load(:release_group, :artist => self.id)).css('release-group').each do |rg|
|
12
12
|
@release_groups << MusicBrainz::ReleaseGroup.parse_xml(rg)
|
13
13
|
end
|
14
14
|
end
|
15
15
|
@release_groups.sort{ |a, b| a.first_release_date <=> b.first_release_date }
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
def self.find mbid
|
19
|
-
res =
|
19
|
+
res = self.load :artist, :id => mbid, :inc => [:url_rels]
|
20
20
|
return nil if res.nil?
|
21
21
|
@artist = self.parse_xml(Nokogiri::XML(res))
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
def self.parse_xml xml
|
25
25
|
@artist = MusicBrainz::Artist.new
|
26
26
|
@artist.id = self.safe_get_attr(xml, 'artist', 'id')
|
@@ -35,21 +35,21 @@ module MusicBrainz
|
|
35
35
|
end
|
36
36
|
@artist
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
def self.discography mbid
|
40
40
|
artist = self.find(mbid)
|
41
41
|
artist.release_groups.each {|rg| rg.releases.each {|r| r.tracks } }
|
42
42
|
artist
|
43
43
|
end
|
44
|
-
|
44
|
+
|
45
45
|
def self.find_by_name name
|
46
46
|
matches = self.search name
|
47
47
|
matches.length.zero? ? nil : self.find(matches.first[:mbid])
|
48
48
|
end
|
49
|
-
|
49
|
+
|
50
50
|
def self.search name
|
51
51
|
artists = []
|
52
|
-
xml = Nokogiri::XML(
|
52
|
+
xml = Nokogiri::XML(self.load(:artist, :query => CGI.escape(name).gsub(/\!/, '\!') + '~', :limit => 50))
|
53
53
|
xml.css('artist-list > artist').each do |a|
|
54
54
|
artist = {
|
55
55
|
:name => a.first_element_child.text.gsub(/[`’]/, "'"),
|
@@ -60,7 +60,13 @@ module MusicBrainz
|
|
60
60
|
:mbid => self.safe_get_attr(a, nil, 'id')
|
61
61
|
}
|
62
62
|
aliases = a.css('alias-list > alias').map{ |item| item.text }
|
63
|
-
if
|
63
|
+
if artist[:name] == name
|
64
|
+
artist[:weight] += 100
|
65
|
+
elsif artist[:name].downcase == name.downcase
|
66
|
+
artist[:weight] += 50
|
67
|
+
elsif artist[:name].downcase.gsub(/\s/, '') == name.downcase.gsub(/\s/, '')
|
68
|
+
artist[:weight] += 25
|
69
|
+
elsif aliases.include? name
|
64
70
|
artist[:weight] += 20
|
65
71
|
elsif aliases.map{ |item| item.downcase }.include? name.downcase
|
66
72
|
artist[:weight] += 10
|
@@ -1,12 +1,17 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
1
2
|
module MusicBrainz
|
2
3
|
class Base
|
3
|
-
def self.safe_get_attr
|
4
|
+
def self.safe_get_attr(xml, path, name)
|
4
5
|
node = path.nil? ? xml : (xml.css(path).first unless xml.css(path).empty?)
|
5
6
|
node.attr(name) unless node.nil? or node.attr(name).nil?
|
6
7
|
end
|
7
|
-
|
8
|
-
def self.safe_get_value
|
8
|
+
|
9
|
+
def self.safe_get_value(xml, path)
|
9
10
|
xml.css(path).first.text unless xml.css(path).empty?
|
10
11
|
end
|
12
|
+
|
13
|
+
def self.load(*args)
|
14
|
+
MusicBrainz::Tools::Proxy.load(*args)
|
15
|
+
end
|
11
16
|
end
|
12
17
|
end
|
@@ -1,23 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
1
2
|
module MusicBrainz
|
2
3
|
class Release < MusicBrainz::Base
|
3
4
|
attr_accessor :id, :title, :status, :format, :date, :country
|
4
5
|
@tracks
|
5
|
-
|
6
|
+
|
6
7
|
def tracks
|
7
8
|
if @tracks.nil? and not self.id.nil?
|
8
9
|
@tracks = []
|
9
|
-
Nokogiri::XML(
|
10
|
+
Nokogiri::XML(self.class.load(:release, :id => self.id, :inc => [:recordings, :media], :limit => 100)).css('medium-list > medium > track-list > track').each do |r|
|
10
11
|
@tracks << MusicBrainz::Track.parse_xml(r)
|
11
12
|
end
|
12
13
|
end
|
13
14
|
@tracks.sort{ |a, b| a.position <=> b.position }
|
14
15
|
end
|
15
|
-
|
16
|
+
|
16
17
|
def self.find mbid
|
17
|
-
xml = Nokogiri::XML(
|
18
|
+
xml = Nokogiri::XML(self.load(:release, :id => mbid, :inc => [:media])).css('release').first
|
18
19
|
self.parse_xml(xml) unless xml.nil?
|
19
20
|
end
|
20
|
-
|
21
|
+
|
21
22
|
def self.parse_xml xml
|
22
23
|
@release = MusicBrainz::Release.new
|
23
24
|
@release.id = self.safe_get_attr(xml, nil, 'id')
|
@@ -1,23 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
1
2
|
module MusicBrainz
|
2
3
|
class ReleaseGroup < MusicBrainz::Base
|
3
4
|
attr_accessor :id, :type, :title, :disambiguation, :first_release_date
|
4
5
|
@releases
|
5
|
-
|
6
|
+
|
6
7
|
def releases
|
7
8
|
if @releases.nil? and not self.id.nil?
|
8
9
|
@releases = []
|
9
|
-
Nokogiri::XML(
|
10
|
+
Nokogiri::XML(self.class.load(:release, :release_group => self.id, :inc => [:media], :limit => 100)).css('release').each do |r|
|
10
11
|
@releases << MusicBrainz::Release.parse_xml(r)
|
11
12
|
end
|
12
13
|
end
|
13
14
|
@releases.sort{ |a, b| a.date <=> b.date }
|
14
15
|
end
|
15
|
-
|
16
|
+
|
16
17
|
def self.find mbid
|
17
|
-
xml = Nokogiri::XML(
|
18
|
+
xml = Nokogiri::XML(self.load(:release_group, :id => mbid)).css('release-group').first
|
18
19
|
self.parse_xml(xml) unless xml.nil?
|
19
20
|
end
|
20
|
-
|
21
|
+
|
21
22
|
def self.parse_xml xml
|
22
23
|
@release_group = MusicBrainz::ReleaseGroup.new
|
23
24
|
@release_group.id = self.safe_get_attr(xml, nil, 'id')
|
@@ -1,12 +1,13 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
1
2
|
module MusicBrainz
|
2
3
|
class Track < MusicBrainz::Base
|
3
4
|
attr_accessor :position, :recording_id, :title, :length
|
4
|
-
|
5
|
+
|
5
6
|
def self.find mbid
|
6
|
-
xml = Nokogiri::XML(
|
7
|
+
xml = Nokogiri::XML(self.load(:recording, :id => mbid))
|
7
8
|
self.parse_xml(xml) unless xml.nil?
|
8
9
|
end
|
9
|
-
|
10
|
+
|
10
11
|
def self.parse_xml xml
|
11
12
|
@track = MusicBrainz::Track.new
|
12
13
|
@track.position = self.safe_get_value(xml, 'position').to_i
|
data/lib/tools/cache.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
module MusicBrainz
|
3
|
+
module Tools
|
4
|
+
class Cache
|
5
|
+
@@cache_path = nil
|
6
|
+
|
7
|
+
def self.cache_path=(path)
|
8
|
+
@@cache_path = path
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.cache_path
|
12
|
+
@@cache_path
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.clear_cache
|
16
|
+
FileUtils.rm_r(@@cache_path) if @@cache_path && File.exist?(@@cache_path)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.cache_contents(url)
|
20
|
+
response = nil
|
21
|
+
url_parts = url.split('/')
|
22
|
+
file_name = url_parts.pop
|
23
|
+
directory = url_parts.pop
|
24
|
+
file_path = @@cache_path ? "#{@@cache_path}/#{directory}/#{file_name}" : nil
|
25
|
+
|
26
|
+
if file_path && File.exist?(file_path)
|
27
|
+
response = File.open(file_path).gets
|
28
|
+
else
|
29
|
+
response = yield
|
30
|
+
|
31
|
+
unless response.nil? or file_path.nil?
|
32
|
+
FileUtils.mkdir_p file_path.split('/')[0..-2].join('/')
|
33
|
+
file = File.new(file_path, 'w')
|
34
|
+
file.puts(response.gets) # .force_encoding('UTF-8')
|
35
|
+
file.chmod(0755)
|
36
|
+
file.close
|
37
|
+
response.rewind
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
response
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|