1
0
Fork 0

Merge branch 'master' of github.com:magnolia-fan/BeatHaven

This commit is contained in:
Gregory Eremin 2011-11-24 14:14:51 +04:00
commit 705b4cfbc2
36 changed files with 841 additions and 53 deletions

View File

@ -20,7 +20,8 @@ gem 'jquery-rails'
# Music related stuff # Music related stuff
gem 'lastfm-client', :git => 'http://github.com/pch/lastfm-client.git' gem 'lastfm-client', :git => 'http://github.com/pch/lastfm-client.git'
gem 'musicbrainz', :require => 'musicbrainz' # gem 'musicbrainz', :require => 'musicbrainz'
gem 'musicbrainz', path: "vendor/plugins/gems/musicbrainz", :require => 'musicbrainz'
# Misc utils # Misc utils
gem 'bitmask_attributes' gem 'bitmask_attributes'

View File

@ -5,6 +5,12 @@ GIT
lastfm-client (0.0.3) lastfm-client (0.0.3)
json (>= 1.4.6) json (>= 1.4.6)
PATH
remote: vendor/plugins/gems/musicbrainz
specs:
musicbrainz (0.5.2)
nokogiri
GEM GEM
remote: http://rubygems.org/ remote: http://rubygems.org/
specs: specs:
@ -40,7 +46,7 @@ GEM
arel (2.2.1) arel (2.2.1)
awesome_print (0.4.0) awesome_print (0.4.0)
bcrypt-ruby (3.0.1) bcrypt-ruby (3.0.1)
bitmask_attributes (0.2.3) bitmask_attributes (0.2.4)
activerecord (~> 3.0) activerecord (~> 3.0)
builder (3.0.0) builder (3.0.0)
coffee-script (2.2.0) coffee-script (2.2.0)
@ -57,7 +63,7 @@ GEM
haml (3.1.3) haml (3.1.3)
hike (1.2.1) hike (1.2.1)
i18n (0.6.0) i18n (0.6.0)
jquery-rails (1.0.17) jquery-rails (1.0.18)
railties (~> 3.0) railties (~> 3.0)
thor (~> 0.14) thor (~> 0.14)
json (1.6.1) json (1.6.1)
@ -69,8 +75,6 @@ GEM
treetop (~> 1.4.8) treetop (~> 1.4.8)
mime-types (1.17.2) mime-types (1.17.2)
multi_json (1.0.3) multi_json (1.0.3)
musicbrainz (0.5.2)
nokogiri
mysql2 (0.3.7) mysql2 (0.3.7)
nokogiri (1.5.0) nokogiri (1.5.0)
pg (0.11.0) pg (0.11.0)
@ -136,7 +140,7 @@ DEPENDENCIES
jquery-rails jquery-rails
json json
lastfm-client! lastfm-client!
musicbrainz musicbrainz!
mysql2 (= 0.3.7) mysql2 (= 0.3.7)
nokogiri nokogiri
pg pg

View File

@ -57,8 +57,9 @@ class window.Player
m = Math.floor(len / 60) m = Math.floor(len / 60)
s = len - Math.floor(len / 60) * 60 s = len - Math.floor(len / 60) * 60
duration = m + ':' + (if s < 10 then '0' else '') + s duration = m + ':' + (if s < 10 then '0' else '') + s
item_class = (if item.available == false then 'unavailable' else '')
$('.playlist').append ' $('.playlist').append '
<li id="i' +Math.round(Math.random() * 999999)+ '" data-id="'+item.id+'"> <li id="i' +Math.round(Math.random() * 999999)+ '" data-id="'+item.id+'" class="'+item_class+'">
<div class="song-duration">' +duration+ '</div> <div class="song-duration">' +duration+ '</div>
<div class="remove">remove</div> <div class="remove">remove</div>
<div class="artist-name">' +item.artist+ '</div> <div class="artist-name">' +item.artist+ '</div>
@ -85,19 +86,26 @@ class window.Player
$('.player .now-playing').html query $('.player .now-playing').html query
$('.playlist li').removeClass 'now' $('.playlist li').removeClass 'now'
$obj.addClass 'now' $obj.addClass 'now'
_vk_music.search track.artist, track.name, track.duration, (audio) -> _vk_music.search track.artist, track.name, track.length, (audio) ->
_player.playSource audio.url if audio is null
if track.length == 0 _session.query '/track/report', { id: track.id }, (r) ->
len = parseInt(audio.duration, 10) if r.status is 'success'
m = Math.floor(len / 60) $('.playlist li[data-id="'+track.id+'"]').addClass("unavailable")
s = len - Math.floor(len / 60) * 60 $($('.album div[data-id="'+track.id+'"]').siblings()[0]).addClass("unavailable")
duration = m + ':' + (if s < 10 then '0' else '') + s _player.setTrack _player.nextTrack()
_session.query '/track/update_length', { track_id: track.id, length: len }, (r) -> else
if r.result is 'success' _player.playSource audio.url
$('.playlist li[data-id="'+track.id+'"] .song-duration').text(duration) if track.length == 0
$($('.album div[data-id="'+track.id+'"]').siblings()[0]).text(duration) len = parseInt(audio.duration, 10)
m = Math.floor(len / 60)
this.updateNowListening track s = len - Math.floor(len / 60) * 60
duration = m + ':' + (if s < 10 then '0' else '') + s
_session.query '/track/update_length', { track_id: track.id, length: len }, (r) ->
if r.status is 'success'
$('.playlist li[data-id="'+track.id+'"] .song-duration').text(duration)
$($('.album div[data-id="'+track.id+'"]').siblings()[0]).text(duration)
_player.updateNowListening track
false
false false
getTrackInfo: (id) -> getTrackInfo: (id) ->
@ -106,6 +114,12 @@ class window.Player
return track return track
false false
getAlbumInfo: (id) ->
for album in _player.albums
if parseInt(album.id, 10) == parseInt(id, 10)
return album
false
hasTrack: -> hasTrack: ->
if $('#jplayer audio').length > 0 if $('#jplayer audio').length > 0
return $('#jplayer audio').attr('src')? and $('#jplayer audio').attr('src') != '' return $('#jplayer audio').attr('src')? and $('#jplayer audio').attr('src') != ''
@ -236,21 +250,19 @@ $('.playlist li').live 'click', ->
# Adding To Playlist actions # Adding To Playlist actions
$('.add-album').live 'click', -> $('.add-album').live 'click', ->
artist = $('.artist-info h2').text() album = _player.getAlbumInfo($(this).attr('data-album-id'))
album = _player.albums[$(this).attr('data-album-id')]
for item in album.tracks for item in album.tracks
item['artist'] = artist item['artist'] = album.artist
item['album'] = album.name item['album'] = album.name
_player.addTracks album.tracks _player.addTracks album.tracks
false false
$('.s-add').live 'click', -> $('.s-add').live 'click', ->
artist = $('.artist-info h2').text() album = _player.getAlbumInfo($(this).attr('data-album-id'))
album = _player.albums[$(this).attr('data-album-id')]
item = album.tracks[$(this).attr('data-id')] item = album.tracks[$(this).attr('data-id')]
for item in album.tracks for item in album.tracks
if item.id == parseInt($(this).attr('data-id'), 10) if item.id == parseInt($(this).attr('data-id'), 10)
item['artist'] = artist item['artist'] = album.artist
item['album'] = album.name item['album'] = album.name
_player.addTracks [item] _player.addTracks [item]
return false return false

View File

@ -4,7 +4,6 @@ class window.Search
$('#search').attr(disabled: 'disabled').blur() $('#search').attr(disabled: 'disabled').blur()
$('#autocomplete-container').hide() $('#autocomplete-container').hide()
$('#artist-load-spinner').show() $('#artist-load-spinner').show()
this.hideSuggestions()
false false
hideSpinner: -> hideSpinner: ->
@ -22,7 +21,8 @@ class window.Search
if _session.getUser().id if _session.getUser().id
if data.artist.albums? if data.artist.albums?
for album in data.artist.albums for album in data.artist.albums
_player.albums[album.id] = album album['artist'] = data.artist.name
_player.albums.push(album)
$('.button-container').show() $('.button-container').show()
_search.hideSpinner() _search.hideSpinner()
if data.status is 'loading' if data.status is 'loading'
@ -42,24 +42,9 @@ class window.Search
_search.hideSpinner() _search.hideSpinner()
alert "Not found" alert "Not found"
false false
showSuggestions: (values) ->
for item in values
$('.suggestions ul').append '
<li>
<a class="data artist">' +item.name+ '</a>
' +(if item.desc? then '<br/><span>'+item.desc+'</span>' else '')+ '
</li>'
$('.suggestions').show()
false
hideSuggestions: ->
$('.suggestions ul li').remove()
$('.suggestions').hide()
false
$('#search-form').live 'submit', -> $('#search-form').live 'submit', ->
$('#autocomplete-container').remove() $('#autocomplete-container').hide()
_search.loadArtistData $('#search').val() _search.loadArtistData $('#search').val()
false false
$('.data.artist').live 'click', -> $('.data.artist').live 'click', ->

View File

@ -59,7 +59,7 @@ class window.VkontakteMusic
data data
prepareQuery: (artist, track) -> prepareQuery: (artist, track) ->
artist+" "+track.replace(/\(.*\)/i, '').split('/')[0] artist+" "+this.trim(/[\w\d\s]+/.exec(track)[0]).replace(/\(.*\)/i, '').split('/')[0]
trim: (str) -> trim: (str) ->
while str.indexOf(' ') isnt -1 while str.indexOf(' ') isnt -1

View File

@ -34,6 +34,9 @@
& > h3 { & > h3 {
margin: -5px 0 5px 0; margin: -5px 0 5px 0;
} }
tr.unavailable > td {
background-color: #FFF0F0;
}
td.song-duration { td.song-duration {
text-align: right; text-align: right;
.s-duration { .s-duration {

View File

@ -109,6 +109,9 @@
margin: 16px 5px 0 0; margin: 16px 5px 0 0;
cursor: pointer; cursor: pointer;
} }
&.unavailable {
background-color: #FFF0F0;
}
&.now { &.now {
background-color: #EAF5FF; background-color: #EAF5FF;
} }

View File

@ -20,6 +20,10 @@
} }
} }
#search-form {
height: 28px !important;
}
#artist-load-spinner { #artist-load-spinner {
display: none; display: none;
float: right; float: right;

View File

@ -15,7 +15,7 @@ class ArtistController < ApplicationController
if results.empty? if results.empty?
return render json: { status: 'not_found' } return render json: { status: 'not_found' }
end end
best_match = results[0][:name] best_match = results[0][:sort_name]
if best_match != artist_name and similar_names(artist_name, best_match) if best_match != artist_name and similar_names(artist_name, best_match)
return render json: { status: 'corrected', correct_name: best_match } return render json: { status: 'corrected', correct_name: best_match }
elsif best_match == artist_name elsif best_match == artist_name

View File

@ -38,8 +38,9 @@ class ImportController < ApplicationController
artist.pic_url = lastfm_artist['artist']['image'][3]['#text'] artist.pic_url = lastfm_artist['artist']['image'][3]['#text']
artist.listeners = lastfm_artist['artist']['stats']['listeners'] artist.listeners = lastfm_artist['artist']['stats']['listeners']
artist.artist_type = brainz_artist.type artist.artist_type = brainz_artist.type
artist.original_name = brainz_artist.name
artist.mbid = brainz_artist.id artist.mbid = brainz_artist.id
artist.save artist.save!
brainz_artist.urls.each do |service, url| brainz_artist.urls.each do |service, url|
ArtistLink.new( ArtistLink.new(

View File

@ -18,7 +18,7 @@ class TrackController < ApplicationController
def report_unavailable def report_unavailable
track = Track.find(params[:id]) track = Track.find(params[:id])
unless track.nil? or track.available unless track.nil? or track.available
track.available = true track.available = false
track.save track.save
return render :json => { :status => :success } return render :json => { :status => :success }
end end

View File

@ -5,7 +5,9 @@
.span4.columns.pic .span4.columns.pic
= image_tag @artist.pic_url unless @artist.pic_url.nil? = image_tag @artist.pic_url unless @artist.pic_url.nil?
.span7.columns.desc .span7.columns.desc
%h2= @artist.name %h2
=@artist.name
%small= " "+@artist.original_name.to_s
= @artist.desc.html_safe unless @artist.desc.nil? = @artist.desc.html_safe unless @artist.desc.nil?
- unless @artist.artist_links.empty? - unless @artist.artist_links.empty?
.service-icons .service-icons
@ -22,10 +24,12 @@
.button-container .button-container
%a.btn.add-album{ :'data-album-id' => album.id }= I18n.t 'player.add' %a.btn.add-album{ :'data-album-id' => album.id }= I18n.t 'player.add'
.span7.columns.tracks .span7.columns.tracks
%h3{ :'data-album-id' => album.id }= album.name + " (" + album.year.to_s + ")" %h3{ :'data-album-id' => album.id }
= album.name
%small= " ("+album.year.to_s+")"
%table.zebra-striped.tracklist %table.zebra-striped.tracklist
- album.tracks.each do |track| - album.tracks.each do |track|
%tr %tr{ class: (track.available == false ? "unavailable" : nil) }
%td.song-title= track.name %td.song-title= track.name
%td.song-duration %td.song-duration
.s-duration= (track.duration != '0:00' ? track.duration : '&nbsp;'.html_safe) .s-duration= (track.duration != '0:00' ? track.duration : '&nbsp;'.html_safe)

View File

@ -4,7 +4,7 @@
%ul.suggestions %ul.suggestions
- @suggestions.each do |artist| - @suggestions.each do |artist|
%li %li
%a.data.artist= artist[:name] %a.data.artist= artist[:sort_name]
&nbsp;( &nbsp;(
= artist[:type] = artist[:type]
) )

View File

@ -13,9 +13,10 @@ Beathaven::Application.routes.draw do
match 'lastfm/scrobble' => 'last_fm#scrobble' match 'lastfm/scrobble' => 'last_fm#scrobble'
match 'track/update_length' => 'track#update_length' match 'track/update_length' => 'track#update_length'
match 'track/report' => 'track#report_unavailable'
match 'settings' => 'user#settings' match 'settings' => 'user#settings'
match 'artist/autocomplete' => 'last_fm#autocomplete' match 'artist/autocomplete' => 'last_fm#autocomplete'
match 'artist/(:name)/' => 'artist#data', :constraints => { :name => /[^\/]*/ } match 'artist/(:name)' => 'artist#data', :constraints => { :name => /.*/ }
end end

15
vendor/plugins/gems/musicbrainz/Gemfile vendored Normal file
View File

@ -0,0 +1,15 @@
source "http://rubygems.org"
group :development do
gem "bundler", "~> 1.0.0"
gem "jeweler", "~> 1.6.4"
gem "rcov", ">= 0"
gem "rdoc", ">= 0"
gem "shoulda"
gem "rspec"
gem "vcr"
gem "webmock"
end
gem "nokogiri", ">= 0"

View File

@ -0,0 +1,44 @@
GEM
remote: http://rubygems.org/
specs:
addressable (2.2.6)
crack (0.3.1)
diff-lcs (1.1.3)
git (1.2.5)
jeweler (1.6.4)
bundler (~> 1.0)
git (>= 1.2.5)
rake
json (1.6.1)
nokogiri (1.5.0)
rake (0.9.2.2)
rcov (0.9.11)
rdoc (3.11)
json (~> 1.4)
rspec (2.7.0)
rspec-core (~> 2.7.0)
rspec-expectations (~> 2.7.0)
rspec-mocks (~> 2.7.0)
rspec-core (2.7.1)
rspec-expectations (2.7.0)
diff-lcs (~> 1.1.2)
rspec-mocks (2.7.0)
shoulda (2.11.3)
vcr (1.11.3)
webmock (1.7.7)
addressable (~> 2.2, > 2.2.5)
crack (>= 0.1.7)
PLATFORMS
ruby
DEPENDENCIES
bundler (~> 1.0.0)
jeweler (~> 1.6.4)
nokogiri
rcov
rdoc
rspec
shoulda
vcr
webmock

View File

@ -0,0 +1,20 @@
Copyright (c) 2011 magnolia-fan
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.

View File

@ -0,0 +1,76 @@
= MusicBrainz Web Service wrapper {<img src="https://secure.travis-ci.org/magnolia-fan/musicbrainz.png"/>}[http://travis-ci.org/magnolia-fan/musicbrainz]
=== Installation
gem install musicbrainz
=== Usage
require 'musicbrainz'
# Search for artists
@suggestions = MusicBrainz::Artist.search('Jet')
# Find artist by name or mbid
@foo_fighters = MusicBrainz::Artist.find_by_name('Foo Fighters')
@kasabian = MusicBrainz::Artist.find('69b39eab-6577-46a4-a9f5-817839092033')
# Use them like ActiveRecord models
@empire_tracks = @kasabian.release_groups[8].releases.first.tracks
=== Api
MusicBrainz::Artist
@artists = MusicBrainz::Artist.search(query)
@artist = MusicBrainz::Artist.find_by_name(name)
@artist = MusicBrainz::Artist.find(mbid)
@artist.id
@artist.type
@artist.name
@artist.country
@artist.date_begin
@artist.date_end
@artist.release_groups
MusicBrainz::ReleaseGroup
@release_group = MusicBrainz::ReleaseGroup.find(mbid)
@release_group.id
@release_group.type
@release_group.title
@release_group.first_release_date
@release_group.releases
MusicBrainz::Release
@release = MusicBrainz::Release.find(mbid)
@release.id
@release.title
@release.status
@release.date
@release.country
@release.tracks
MusicBrainz::Track
@track = MusicBrainz::Track.find(mbid)
@track.position
@track.recording_id
@track.title
@track.length
=== Contributing
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
* Fork the project
* Start a feature/bugfix branch
* Commit and push until you are happy with your contribution
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
* 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.
=== Copyright
Copyright (c) 2011 Gregory Eremin. See LICENSE.txt for further details.

View File

@ -0,0 +1,53 @@
# encoding: utf-8
require 'rubygems'
require 'bundler'
begin
Bundler.setup(:default, :development)
rescue Bundler::BundlerError => e
$stderr.puts e.message
$stderr.puts "Run `bundle install` to install missing gems"
exit e.status_code
end
require 'rake'
require 'jeweler'
Jeweler::Tasks.new do |gem|
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
gem.name = "musicbrainz"
gem.homepage = "http://github.com/magnolia-fan/musicbrainz"
gem.license = "MIT"
gem.summary = %Q{MusicBrainz Web Service wrapper}
gem.description = %Q{MusicBrainz Web Service wrapper with ActiveRecord-style models}
gem.email = "magnolia_fan@me.com"
gem.authors = ["Gregory Eremin"]
# dependencies defined in Gemfile
end
Jeweler::RubygemsDotOrgTasks.new
require 'rake/testtask'
Rake::TestTask.new(:test) do |test|
test.libs << 'lib' << 'test'
test.pattern = 'test/**/test_*.rb'
test.verbose = true
end
require 'rcov/rcovtask'
Rcov::RcovTask.new do |test|
test.libs << 'test'
test.pattern = 'test/**/test_*.rb'
test.verbose = true
test.rcov_opts << '--exclude "gems/*"'
end
task :default => :test
require 'rdoc/task'
RDoc::Task.new do |rdoc|
version = File.exist?('VERSION') ? File.read('VERSION') : ""
rdoc.rdoc_dir = 'rdoc'
rdoc.title = "musicbrainz #{version}"
rdoc.rdoc_files.include('README*')
rdoc.rdoc_files.include('lib/**/*.rb')
end

View File

@ -0,0 +1 @@
0.5.2

View File

@ -0,0 +1,38 @@
module MusicBrainz
@@last_query_time = 0
@@query_interval = 1.5 # Min: 1.0 Safe: 1.5
WEB_SERVICE_URL = 'http://musicbrainz.org/ws/2/'
USER_AGENT = "gem musicbrainz (https://github.com/magnolia-fan/musicbrainz) @ " + Socket.gethostname
def self.query_interval= sec
@@query_interval = sec.to_f
end
def self.load resourse, params = {}
url = WEB_SERVICE_URL + resourse.to_s.gsub('_', '-') + '/' + (params[:id].to_s || '')
params.delete(:id) unless params[:id].nil?
url << '?' + params.map{ |k, v|
k.to_s.gsub('_', '-') + '=' + (v.is_a?(Array) ? v.map{ |_| _.to_s.gsub('_', '-') }.join('+') : v.to_s)
}.join('&') unless params.empty?
self.get_contents url
end
private
def self.get_contents url
time_passed = Time.now.to_f - @@last_query_time
sleep @@query_interval - time_passed if time_passed < @@query_interval
response = nil
5.times do
begin
response = open(URI.encode(url), "User-Agent" => USER_AGENT)
@@last_query_time = Time.now.to_f
rescue => e
return nil if e.io.status[0].to_i == 404
end
break unless response.nil?
end
response
end
end

View File

@ -0,0 +1,75 @@
# encoding: UTF-8
module MusicBrainz
class Artist < MusicBrainz::Base
attr_accessor :id, :type, :name, :country, :date_begin, :date_end, :urls
@release_groups
def release_groups
if @release_groups.nil? and not self.id.nil?
@release_groups = []
Nokogiri::XML(MusicBrainz.load(:release_group, :artist => self.id)).css('release-group').each do |rg|
@release_groups << MusicBrainz::ReleaseGroup.parse_xml(rg)
end
end
@release_groups.sort{ |a, b| a.first_release_date <=> b.first_release_date }
end
def self.find mbid
res = MusicBrainz.load :artist, :id => mbid, :inc => [:url_rels]
return nil if res.nil?
@artist = self.parse_xml(Nokogiri::XML(res))
end
def self.parse_xml xml
@artist = MusicBrainz::Artist.new
@artist.id = self.safe_get_attr(xml, 'artist', 'id')
@artist.type = self.safe_get_attr(xml, 'artist', 'type')
@artist.name = self.safe_get_value(xml, 'artist > name').gsub(/[`]/, "'")
@artist.country = self.safe_get_value(xml, 'artist > country')
@artist.date_begin = self.safe_get_value(xml, 'artist > life-span > begin')
@artist.date_end = self.safe_get_value(xml, 'artist > life-span > end')
@artist.urls = {}
xml.css('relation-list[target-type="url"] > relation').each do |rel|
@artist.urls[rel.attr('type').downcase.split(' ').join('_').to_sym] = rel.css('target').text
end
@artist
end
def self.discography mbid
artist = self.find(mbid)
artist.release_groups.each {|rg| rg.releases.each {|r| r.tracks } }
artist
end
def self.find_by_name name
matches = self.search name
matches.length.zero? ? nil : self.find(matches.first[:mbid])
end
def self.search name
artists = []
xml = Nokogiri::XML(MusicBrainz.load(:artist, :query => name.gsub(/\!/, '\!').gsub(/\s/, '+') + '~', :limit => 50))
xml.css('artist-list > artist').each do |a|
artist = {
:name => a.first_element_child.text.gsub(/[`]/, "'"),
:sort_name => self.safe_get_value(a, 'sort-name').gsub(/[`]/, "'"),
:weight => 0,
:desc => self.safe_get_value(a, 'disambiguation'),
:type => self.safe_get_attr(a, nil, 'type'),
:mbid => self.safe_get_attr(a, nil, 'id')
}
aliases = a.css('alias-list > alias').map{ |item| item.text }
if aliases.include? name
artist[:weight] += 20
elsif aliases.map{ |item| item.downcase }.include? name.downcase
artist[:weight] += 10
elsif aliases.map{ |item| item.downcase.gsub(/\s/, '') }.include? name.downcase.gsub(/\s/, '')
artist[:weight] += 5
end
artists << artist
end
artists.sort{ |a, b| b[:weight] <=> a[:weight] }.take(10)
end
end
end

View File

@ -0,0 +1,12 @@
module MusicBrainz
class Base
def self.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 self.safe_get_value xml, path
xml.css(path).first.text unless xml.css(path).empty?
end
end
end

View File

@ -0,0 +1,41 @@
module MusicBrainz
class Release < MusicBrainz::Base
attr_accessor :id, :title, :status, :format, :date, :country
@tracks
def tracks
if @tracks.nil? and not self.id.nil?
@tracks = []
Nokogiri::XML(MusicBrainz.load(:release, :id => self.id, :inc => [:recordings, :media], :limit => 100)).css('medium-list > medium > track-list > track').each do |r|
@tracks << MusicBrainz::Track.parse_xml(r)
end
end
@tracks.sort{ |a, b| a.position <=> b.position }
end
def self.find mbid
xml = Nokogiri::XML(MusicBrainz.load(:release, :id => mbid, :inc => [:media])).css('release').first
self.parse_xml(xml) unless xml.nil?
end
def self.parse_xml xml
@release = MusicBrainz::Release.new
@release.id = self.safe_get_attr(xml, nil, 'id')
@release.title = self.safe_get_value(xml, 'title')
@release.status = self.safe_get_value(xml, 'status')
@release.format = self.safe_get_value(xml, 'medium-list > medium > format')
date = xml.css('date').empty? ? '2030-12-31' : xml.css('date').text
if date.length == 0
date = '2030-12-31'
elsif date.length == 4
date += '-12-31'
elsif date.length == 7
date += '-31'
end
date = date.split('-')
@release.date = Time.utc(date[0], date[1], date[2])
@release.country = self.safe_get_value(xml, 'country')
@release
end
end
end

View File

@ -0,0 +1,40 @@
module MusicBrainz
class ReleaseGroup < MusicBrainz::Base
attr_accessor :id, :type, :title, :disambiguation, :first_release_date
@releases
def releases
if @releases.nil? and not self.id.nil?
@releases = []
Nokogiri::XML(MusicBrainz.load(:release, :release_group => self.id, :inc => [:media], :limit => 100)).css('release').each do |r|
@releases << MusicBrainz::Release.parse_xml(r)
end
end
@releases.sort{ |a, b| a.date <=> b.date }
end
def self.find mbid
xml = Nokogiri::XML(MusicBrainz.load(:release_group, :id => mbid)).css('release-group').first
self.parse_xml(xml) unless xml.nil?
end
def self.parse_xml xml
@release_group = MusicBrainz::ReleaseGroup.new
@release_group.id = self.safe_get_attr(xml, nil, 'id')
@release_group.type = self.safe_get_attr(xml, nil, 'type')
@release_group.title = self.safe_get_value(xml, 'title')
@release_group.disambiguation = self.safe_get_value(xml, 'disambiguation')
date = xml.css('first-release-date').empty? ? '2030-12-31' : xml.css('first-release-date').text
if date.length == 0
date = '2030-12-31'
elsif date.length == 4
date += '-12-31'
elsif date.length == 7
date += '-31'
end
date = date.split('-')
@release_group.first_release_date = Time.utc(date[0], date[1], date[2])
@release_group
end
end
end

View File

@ -0,0 +1,20 @@
module MusicBrainz
class Track < MusicBrainz::Base
attr_accessor :position, :recording_id, :title, :length
def self.find mbid
xml = Nokogiri::XML(MusicBrainz.load(:recording, :id => mbid))
self.parse_xml(xml) unless xml.nil?
end
def self.parse_xml xml
@track = MusicBrainz::Track.new
@track.position = self.safe_get_value(xml, 'position').to_i
@track.recording_id = self.safe_get_attr(xml, 'recording', 'id')
@track.title = self.safe_get_value(xml, 'recording > title')
@track.length = self.safe_get_value(xml, 'length').to_i
@track.length = self.safe_get_value(xml, 'recording > length').to_i
@track
end
end
end

View File

@ -0,0 +1,11 @@
require "open-uri"
require "socket"
require "nokogiri"
require "cgi"
require "models/music_brainz"
require "models/music_brainz/base"
require "models/music_brainz/artist"
require "models/music_brainz/release_group"
require "models/music_brainz/release"
require "models/music_brainz/track"

View File

@ -0,0 +1,86 @@
# Generated by jeweler
# DO NOT EDIT THIS FILE DIRECTLY
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
# -*- encoding: utf-8 -*-
Gem::Specification.new do |s|
s.name = %q{musicbrainz}
s.version = "0.5.2"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Gregory Eremin"]
s.date = %q{2011-11-15}
s.description = %q{MusicBrainz Web Service wrapper with ActiveRecord-style models}
s.email = %q{magnolia_fan@me.com}
s.extra_rdoc_files = [
"LICENSE.txt",
"README.rdoc"
]
s.files = [
".document",
".travis.yml",
"Gemfile",
"LICENSE.txt",
"README.rdoc",
"Rakefile",
"VERSION",
"lib/models/music_brainz.rb",
"lib/models/music_brainz/artist.rb",
"lib/models/music_brainz/base.rb",
"lib/models/music_brainz/release.rb",
"lib/models/music_brainz/release_group.rb",
"lib/models/music_brainz/track.rb",
"lib/musicbrainz.rb",
"musicbrainz.gemspec",
"spec/requests/artist_spec.rb",
"spec/spec_helper.rb",
"spec/support/vcr.rb",
"test/helper.rb",
"test/test_musicbrainz_artist.rb",
"test/test_musicbrainz_release.rb",
"test/test_musicbrainz_release_group.rb",
"test/test_musicbrainz_track.rb"
]
s.homepage = %q{http://github.com/magnolia-fan/musicbrainz}
s.licenses = ["MIT"]
s.require_paths = ["lib"]
s.rubygems_version = %q{1.6.2}
s.summary = %q{MusicBrainz Web Service wrapper}
if s.respond_to? :specification_version then
s.specification_version = 3
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
s.add_runtime_dependency(%q<nokogiri>, [">= 0"])
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
s.add_development_dependency(%q<rcov>, [">= 0"])
s.add_development_dependency(%q<rdoc>, [">= 0"])
s.add_development_dependency(%q<shoulda>, [">= 0"])
s.add_development_dependency(%q<rspec>, [">= 0"])
s.add_development_dependency(%q<vcr>, [">= 0"])
s.add_development_dependency(%q<webmock>, [">= 0"])
else
s.add_dependency(%q<nokogiri>, [">= 0"])
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
s.add_dependency(%q<rcov>, [">= 0"])
s.add_dependency(%q<rdoc>, [">= 0"])
s.add_dependency(%q<shoulda>, [">= 0"])
s.add_dependency(%q<rspec>, [">= 0"])
s.add_dependency(%q<vcr>, [">= 0"])
s.add_dependency(%q<webmock>, [">= 0"])
end
else
s.add_dependency(%q<nokogiri>, [">= 0"])
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
s.add_dependency(%q<rcov>, [">= 0"])
s.add_dependency(%q<rdoc>, [">= 0"])
s.add_dependency(%q<shoulda>, [">= 0"])
s.add_dependency(%q<rspec>, [">= 0"])
s.add_dependency(%q<vcr>, [">= 0"])
s.add_dependency(%q<webmock>, [">= 0"])
end
end

View File

@ -0,0 +1,44 @@
require 'spec_helper'
describe "artist" do
it "return valid instance", :vcr do
artist = MusicBrainz::Artist.find('69b39eab-6577-46a4-a9f5-817839092033')
artist.should be_a_kind_of(MusicBrainz::Artist)
end
it "search by name", :vcr do
matches = MusicBrainz::Artist.search('Kasabian')
matches.should have_at_least(1).item
matches.first[:name].should eql('Kasabian')
end
#
# should "get correct result by name" do
# @artist = MusicBrainz::Artist.find_by_name('Kasabian')
# assert_equal("69b39eab-6577-46a4-a9f5-817839092033", @artist.id)
# end
#
# setup do
# @artist = MusicBrainz::Artist.find('69b39eab-6577-46a4-a9f5-817839092033')
# end
#
# should "return valid instance" do
# assert_instance_of(MusicBrainz::Artist, @artist)
# end
#
# should "contain correct data" do
# assert_equal("69b39eab-6577-46a4-a9f5-817839092033", @artist.id)
# assert_equal("Group", @artist.type)
# assert_equal("Kasabian", @artist.name)
# assert_equal("GB", @artist.country)
# assert_equal("1999", @artist.date_begin)
# end
#
# should "load release groups" do
# release_groups = @artist.release_groups
# assert_operator(16, :<=, release_groups.length)
# assert_equal('533cbc5f-ec7e-32ab-95f3-8d1f804a5176', release_groups.first.id)
# assert_equal('Single', release_groups.first.type)
# assert_equal('Club Foot', release_groups.first.title)
# assert_equal(Time.utc(2004, 5, 10), release_groups.first.first_release_date)
# end
end

View File

@ -0,0 +1,19 @@
require 'rubygems'
require 'bundler'
begin
Bundler.setup(:default, :development)
rescue Bundler::BundlerError => e
$stderr.puts e.message
$stderr.puts "Run `bundle install` to install missing gems"
exit e.status_code
end
require "vcr"
require "musicbrainz"
# HTTPI.log = false
Dir[File.dirname(__FILE__)+"/../lib/*.rb"].each{ |f| require f }
Dir[File.dirname(__FILE__)+"/../spec/support/*.rb"].each{ |f| require f }
RSpec.configure do |config|
config.mock_with :rspec
end

View File

@ -0,0 +1,13 @@
VCR.config do |c|
c.cassette_library_dir = File.join(File.dirname(__FILE__), '..', '..', 'tmp', 'vcr')
c.stub_with :webmock
c.default_cassette_options = { :record => :new_episodes }
end
RSpec.configure do |c|
c.treat_symbols_as_metadata_keys_with_true_values = true
c.around(:each, :vcr) do |example|
name = example.metadata[:full_description].gsub(/\s/, '_')
VCR.use_cassette(name) { example.call }
end
end

View File

@ -0,0 +1,18 @@
require 'rubygems'
require 'bundler'
begin
Bundler.setup(:default, :test)
rescue Bundler::BundlerError => e
$stderr.puts e.message
$stderr.puts "Run `bundle install` to install missing gems"
exit e.status_code
end
require 'test/unit'
require 'shoulda'
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
$LOAD_PATH.unshift(File.dirname(__FILE__))
require 'musicbrainz'
class Test::Unit::TestCase
end

View File

@ -0,0 +1,47 @@
require 'helper'
class TestMusicbrainzArtist < Test::Unit::TestCase
context "artist" do
should "load artist xml" do
assert_nothing_raised(Exception) do
MusicBrainz::Artist.find('69b39eab-6577-46a4-a9f5-817839092033')
end
end
should "search by name" do
matches = MusicBrainz::Artist.search('Kasabian')
assert_operator(0, :<, matches.length)
assert_equal("Kasabian", matches.first[:name])
end
should "get correct result by name" do
@artist = MusicBrainz::Artist.find_by_name('Kasabian')
assert_equal("69b39eab-6577-46a4-a9f5-817839092033", @artist.id)
end
setup do
@artist = MusicBrainz::Artist.find('69b39eab-6577-46a4-a9f5-817839092033')
end
should "return valid instance" do
assert_instance_of(MusicBrainz::Artist, @artist)
end
should "contain correct data" do
assert_equal("69b39eab-6577-46a4-a9f5-817839092033", @artist.id)
assert_equal("Group", @artist.type)
assert_equal("Kasabian", @artist.name)
assert_equal("GB", @artist.country)
assert_equal("1999", @artist.date_begin)
end
should "load release groups" do
release_groups = @artist.release_groups
assert_operator(16, :<=, release_groups.length)
assert_equal('533cbc5f-ec7e-32ab-95f3-8d1f804a5176', release_groups.first.id)
assert_equal('Single', release_groups.first.type)
assert_equal('Club Foot', release_groups.first.title)
assert_equal(Time.utc(2004, 5, 10), release_groups.first.first_release_date)
end
end
end

View File

@ -0,0 +1,36 @@
require 'helper'
class TestMusicbrainzRelease < Test::Unit::TestCase
context "release" do
should "load xml" do
assert_nothing_raised(Exception) do
MusicBrainz::Release.find('2225dd4c-ae9a-403b-8ea0-9e05014c778f')
end
end
setup do
@release = MusicBrainz::Release.find('2225dd4c-ae9a-403b-8ea0-9e05014c778f')
end
should "return valid instance" do
assert_instance_of(MusicBrainz::Release, @release)
end
should "contain correct data" do
assert_equal("2225dd4c-ae9a-403b-8ea0-9e05014c778f", @release.id)
assert_equal("Empire", @release.title)
assert_equal("Official", @release.status)
assert_equal(Time.utc(2006, 8, 28), @release.date)
assert_equal("GB", @release.country)
end
should "load tracks" do
tracks = @release.tracks
assert_equal(11, tracks.length)
assert_equal(1, tracks.first.position)
assert_equal('b3015bab-1540-4d4e-9f30-14872a1525f7', tracks.first.recording_id)
assert_equal('Empire', tracks.first.title)
assert_equal(233013, tracks.first.length)
end
end
end

View File

@ -0,0 +1,36 @@
require 'helper'
class TestMusicbrainzReleaseGroup < Test::Unit::TestCase
context "release group" do
should "load xml" do
assert_nothing_raised(Exception) do
MusicBrainz::ReleaseGroup.find('6f33e0f0-cde2-38f9-9aee-2c60af8d1a61')
end
end
setup do
@release_group = MusicBrainz::ReleaseGroup.find('6f33e0f0-cde2-38f9-9aee-2c60af8d1a61')
end
should "return valid instance" do
assert_instance_of(MusicBrainz::ReleaseGroup, @release_group)
end
should "contain correct data" do
assert_equal("6f33e0f0-cde2-38f9-9aee-2c60af8d1a61", @release_group.id)
assert_equal("Album", @release_group.type)
assert_equal("Empire", @release_group.title)
assert_equal(Time.utc(2006, 8, 28), @release_group.first_release_date)
end
should "load releases" do
releases = @release_group.releases
assert_operator(5, :<=, releases.length)
assert_equal('2225dd4c-ae9a-403b-8ea0-9e05014c778f', releases.first.id)
assert_equal('Official', releases.first.status)
assert_equal('Empire', releases.first.title)
assert_equal(Time.utc(2006, 8, 28), releases.first.date)
assert_equal('GB', releases.first.country)
end
end
end

View File

@ -0,0 +1,25 @@
require 'helper'
class TestMusicbrainzTrack < Test::Unit::TestCase
context "track" do
should "load xml" do
assert_nothing_raised(Exception) do
MusicBrainz::Track.find('b3015bab-1540-4d4e-9f30-14872a1525f7')
end
end
setup do
@track = MusicBrainz::Track.find('b3015bab-1540-4d4e-9f30-14872a1525f7')
end
should "return valid instance" do
assert_instance_of(MusicBrainz::Track, @track)
end
should "contain correct data" do
assert_equal("b3015bab-1540-4d4e-9f30-14872a1525f7", @track.recording_id)
assert_equal("Empire", @track.title)
assert_equal(233013, @track.length)
end
end
end