mostscrobbled 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .DS_Store
6
+ doc/*
7
+ .yardoc/*
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in mostplayed.gemspec
4
+ gemspec
data/README.rdoc ADDED
@@ -0,0 +1,33 @@
1
+ = Mostscrobbled
2
+
3
+ Extracts the artists from a {last.fm}[http://last.fm] user's music library and turns them into nice ruby objects.
4
+
5
+ {Official Documentation}[http://rubydoc.info/github/paulsturgess/mostscrobbled/master/frames]
6
+
7
+ == Usage
8
+
9
+ Before you start you'll need:
10
+ * {A last.fm account}[http://last.fm]
11
+ * {A last.fm api key}[http://last.fm/api]
12
+
13
+ Example:
14
+
15
+ require 'rubygems'
16
+ require 'mostscrobbled'
17
+
18
+ # The main method call returns an array of artists ordered by the number of scrobbles
19
+ artists = Mostscrobbled.find(:username => "foobar", :api_key => "123abc")
20
+
21
+ my_favourite_artist = artists.first
22
+
23
+ # Artists have a number of methods to easily access the attributes returned by the last.fm api
24
+ # For example...
25
+ my_favourite_artist.name # => "Bibio"
26
+ my_favourite_artist.playcount # => "391"
27
+ my_favourite_artist.url # => "http://www.last.fm/music/Bibio"
28
+ my_favourite_artist.mbid # => "9f9953f0-68bb-4ce3-aace-2f44c87f0aa3"
29
+ my_favourite_artist.image_small # => "http://userserve-ak.last.fm/serve/34/39790231.jpg"
30
+
31
+ == Installation
32
+
33
+ gem install mostscrobbled
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,14 @@
1
+ module Mostscrobbled
2
+
3
+ def self.find(opts = {})
4
+ begin
5
+ Mostscrobbled::LastFm::Connection.new(opts).artists
6
+ rescue Mostscrobbled::LastFm::Error => e
7
+ puts e
8
+ end
9
+ end
10
+
11
+ end
12
+
13
+ require 'mostscrobbled/last_fm'
14
+ require 'mostscrobbled/artist'
@@ -0,0 +1,25 @@
1
+ module Mostscrobbled
2
+ class Artist
3
+
4
+ attr_accessor :name, :playcount, :tagcount, :mbid, :url, :streamable, :image_small, :image_medium, :image_large, :image_extralarge, :image_mega
5
+
6
+ def initialize(attrs = {}, *args)
7
+ super(*args)
8
+ attrs.each do |k,v|
9
+ self.send "#{k}=", v
10
+ end
11
+ end
12
+
13
+ def self.build_artist(node)
14
+ (artist = Artist.new).tap do
15
+ [:name, :playcount, :tagcount, :mbid, :url, :streamable].each do |attribute|
16
+ artist.send("#{attribute}=", node.xpath(".//#{attribute}").first.content)
17
+ end
18
+ node.xpath(".//image").each do |image_node| # set :image_small, :image_medium, :image_large, :image_extralarge, :image_mega
19
+ artist.send("image_#{image_node.attributes["size"].value}=", image_node.children.first.content) if image_node.children.first
20
+ end
21
+ end
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,62 @@
1
+ require 'nokogiri'
2
+ require 'open-uri'
3
+ require 'net/http'
4
+
5
+ module Mostscrobbled
6
+ module LastFm
7
+ class Error < StandardError; end
8
+ class ResponseError < Error; end
9
+ class ConfigError < Error; end
10
+ class Connection
11
+
12
+ REQUIRED_ATTRIBUTES = :username, :api_key
13
+ attr_accessor *(REQUIRED_ATTRIBUTES)
14
+
15
+ def initialize(opts = {})
16
+ raise ConfigError, missing_options(opts).map{ |argument| ":#{argument} argument missing" }.join(" and ") unless missing_options(opts).empty?
17
+ opts.keys.each{ |key| send("#{key}=", opts[key]) }
18
+ end
19
+
20
+ # Returns an array of MostscrobbledArtist objects
21
+ def artists
22
+ (artists = []).tap do
23
+ total_artist_pages.times do |page|
24
+ artists_xml(page).xpath('//artist').collect do |node|
25
+ artists << Mostscrobbled::Artist.build_artist(node)
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ def artists_uri(page_number = nil)
32
+ URI.parse("http://ws.audioscrobbler.com/2.0/?method=library.getartists&api_key=#{api_key}&user=#{username}#{"&page=#{page_number + 1}" if page_number}")
33
+ end
34
+
35
+ def artists_xml(page_number = nil)
36
+ uri = artists_uri(page_number)
37
+ http = Net::HTTP.new(uri.host)
38
+ request = Net::HTTP::Get.new(uri.request_uri)
39
+ response = http.request(request)
40
+ case response.code
41
+ when "200"
42
+ @artists_xml ||= {}
43
+ @artists_xml[page_number || 0] ||= Nokogiri::XML(response.body)
44
+ when "403"
45
+ raise ResponseError, Nokogiri::XML(response.body).xpath(".//error").first.content.inspect
46
+ end
47
+ end
48
+
49
+ def total_artist_pages
50
+ artists_xml.xpath('//artists').first["totalPages"].to_i
51
+ end
52
+
53
+ private
54
+
55
+ def missing_options(opts)
56
+ REQUIRED_ATTRIBUTES.select{ |argument| opts[argument].nil? }
57
+ end
58
+
59
+ end
60
+
61
+ end
62
+ end
@@ -0,0 +1,3 @@
1
+ module Mostscrobbled
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "mostscrobbled/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "mostscrobbled"
7
+ s.version = Mostscrobbled::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Paul Sturgess"]
10
+ s.email = ["paulsturgess@gmail.com"]
11
+ s.homepage = ""
12
+ s.summary = "Extracts your most scrobbled artists from last.fm and turns them into nice ruby objects"
13
+ s.description = "Uses the last.fm api to analyse your scrobbles library and extracts the artists out in order of number of scrobbles"
14
+
15
+ s.rubyforge_project = "mostscrobbled"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_runtime_dependency "nokogiri", "~> 1.4"
23
+ s.add_development_dependency "rspec", "~> 2.0.0.beta.22"
24
+ s.add_development_dependency "fakeweb", "~> 1.3.0"
25
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper.rb'
2
+
3
+ describe Mostscrobbled::Artist do
4
+
5
+ context "when inititalizing an artist" do
6
+ let(:artist) {Mostscrobbled::Artist.new(:name => "Bibio", :mbid => "123", :playcount => 200)}
7
+
8
+ it "should set the name" do
9
+ artist.name.should == "Bibio"
10
+ end
11
+
12
+ it "should set the mbid" do
13
+ artist.mbid.should == "123"
14
+ end
15
+
16
+ it "should set the scrobbles_count" do
17
+ artist.playcount.should == 200
18
+ end
19
+ end
20
+
21
+ end
@@ -0,0 +1,3 @@
1
+ <lfm status="failed">
2
+ <error code="6">No user with that name</error>
3
+ </lfm>
@@ -0,0 +1,30 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <lfm status="ok">
3
+ <artists user="timberford" page="1" perPage="50" totalPages="1" total="2">
4
+ <artist>
5
+ <name>Bibio</name>
6
+ <playcount>391</playcount>
7
+ <tagcount>0</tagcount>
8
+ <mbid>9f9953f0-68bb-4ce3-aace-2f44c87f0aa3</mbid>
9
+ <url>http://www.last.fm/music/Bibio</url>
10
+ <streamable>1</streamable>
11
+ <image size="small">http://userserve-ak.last.fm/serve/34/27532381.jpg</image>
12
+ <image size="medium">http://userserve-ak.last.fm/serve/64/27532381.jpg</image>
13
+ <image size="large">http://userserve-ak.last.fm/serve/126/27532381.jpg</image>
14
+ <image size="extralarge">http://userserve-ak.last.fm/serve/252/27532381.jpg</image>
15
+ <image size="mega">http://userserve-ak.last.fm/serve/500/27532381/Bibio+flap+flap.jpg</image>
16
+ </artist>
17
+ <artist>
18
+ <name>Bonobo</name>
19
+ <playcount>387</playcount>
20
+ <tagcount>0</tagcount>
21
+ <mbid>9a709693-b4f8-4da9-8cc1-038c911a61be</mbid>
22
+ <url>http://www.last.fm/music/Bonobo</url>
23
+ <streamable>1</streamable>
24
+ <image size="small">http://userserve-ak.last.fm/serve/34/53939783.png</image>
25
+ <image size="medium">http://userserve-ak.last.fm/serve/64/53939783.png</image>
26
+ <image size="large">http://userserve-ak.last.fm/serve/126/53939783.png</image>
27
+ <image size="extralarge">http://userserve-ak.last.fm/serve/252/53939783.png</image>
28
+ <image size="mega"></image>
29
+ </artist>
30
+ </artists></lfm>
@@ -0,0 +1,92 @@
1
+ require 'spec_helper.rb'
2
+
3
+ describe Mostscrobbled::LastFm::Connection do
4
+
5
+ before { FakeWeb.allow_net_connect = false }
6
+ after { FakeWeb.allow_net_connect = true }
7
+
8
+ let(:connection) {Mostscrobbled::LastFm::Connection.new(:username => "johnsmith", :api_key => "023456789")}
9
+
10
+
11
+ context "when intializing a connection with valid argument" do
12
+ it "should set the username" do
13
+ connection.username.should == "johnsmith"
14
+ end
15
+ it "should set the api_key" do
16
+ connection.api_key.should == "023456789"
17
+ end
18
+ end
19
+
20
+ context "when initializing a connection without the username argument" do
21
+ it "should raise an exception" do
22
+ lambda {Mostscrobbled::LastFm::Connection.new(:api_key => "123")}.should raise_exception(Mostscrobbled::LastFm::ConfigError)
23
+ end
24
+ end
25
+
26
+ context "when initializing a connection without the api_key argument" do
27
+ it "should raise an exception" do
28
+ lambda {Mostscrobbled::LastFm::Connection.new(:username => "John")}.should raise_exception(Mostscrobbled::LastFm::ConfigError)
29
+ end
30
+ end
31
+
32
+ describe "artists_uri" do
33
+ context "when not providing a page number" do
34
+ it "should set the artists uri without a page number" do
35
+ connection.artists_uri.should == URI.parse("http://ws.audioscrobbler.com/2.0/?method=library.getartists&api_key=023456789&user=johnsmith")
36
+ end
37
+ end
38
+ context "when providing a page number" do
39
+ it "should set the artists uri with a page number" do
40
+ connection.artists_uri(2).should == URI.parse("http://ws.audioscrobbler.com/2.0/?method=library.getartists&api_key=023456789&user=johnsmith&page=3")
41
+ end
42
+ end
43
+ end
44
+
45
+ # Note that you cannot compare two Nokogiri documents that have been parsed, even if you are parsing the same document
46
+ # In any case we're not testing that Nokogiri works, we're testing that Nokogiri is called with the correct options
47
+ describe "artists_xml" do
48
+ context "when the result is ok" do
49
+ before do
50
+ FakeWeb.register_uri(:get, "http://example.com", :body => File.read("spec/fixtures/artists_ok.xml"))
51
+ connection.stub(:artists_uri){URI.parse("http://example.com")}
52
+ end
53
+ it "should call the artists url with Nokogiri parse to get the xml" do
54
+ Nokogiri::XML::Document.should_receive(:parse).with(Net::HTTP.get(URI.parse("http://example.com")), nil, nil, 1)
55
+ connection.artists_xml
56
+ end
57
+ it "should not raise the error message as an exception" do
58
+ lambda {connection.artists_xml}.should_not raise_exception(Mostscrobbled::LastFm::ResponseError)
59
+ end
60
+ end
61
+ context "when the result is failed" do
62
+ before do
63
+ FakeWeb.register_uri(:get, "http://example.com", :body => File.read("spec/fixtures/artists_failed.xml"), :status => ["403", "Forbidden"])
64
+ connection.stub(:artists_uri){URI.parse("http://example.com")}
65
+ end
66
+ it "should raise the a ResponseError exception" do
67
+ lambda {connection.artists_xml}.should raise_exception(Mostscrobbled::LastFm::ResponseError)
68
+ end
69
+ end
70
+ end
71
+
72
+ describe "total_artist_pages" do
73
+ before { connection.stub(:artists_xml).and_return(Nokogiri::XML(File.read("spec/fixtures/artists_ok.xml"))) }
74
+ it "should return the correct number of pages" do
75
+ connection.total_artist_pages.should == 1
76
+ end
77
+ end
78
+
79
+ describe "artists" do
80
+ before do
81
+ connection.stub(:total_artist_pages){1}
82
+ connection.stub(:artists_xml).and_return(Nokogiri::XML(File.read("spec/fixtures/artists_ok.xml")))
83
+ end
84
+ it "should include the artists returned by artists_xml" do
85
+ connection.artists.map(&:name).should include("Bibio")
86
+ connection.artists.map(&:name).should include("Bonobo")
87
+ connection.artists.first.should be_kind_of(Mostscrobbled::Artist)
88
+ connection.artists.length.should == 2
89
+ end
90
+ end
91
+
92
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper.rb'
2
+
3
+ describe Mostscrobbled do
4
+
5
+ context "when intializing Mostscrobbled" do
6
+ it "should create a lastfm connection and call artists on it" do
7
+ connection = mock(Mostscrobbled::LastFm::Connection)
8
+ Mostscrobbled::LastFm::Connection.should_receive(:new).with(:username => "john", :api_key => "123") {connection}
9
+ connection.should_receive(:artists)
10
+ Mostscrobbled.find(:username => "john", :api_key => "123")
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,2 @@
1
+ Dir["#{File.dirname(__FILE__)}/../lib/**/*.rb"].each { |f| require f }
2
+ require 'fakeweb'
metadata ADDED
@@ -0,0 +1,109 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mostscrobbled
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Paul Sturgess
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-07-13 00:00:00 +01:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: nokogiri
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ~>
23
+ - !ruby/object:Gem::Version
24
+ version: "1.4"
25
+ type: :runtime
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ prerelease: false
30
+ requirement: &id002 !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - ~>
34
+ - !ruby/object:Gem::Version
35
+ version: 2.0.0.beta.22
36
+ type: :development
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: fakeweb
40
+ prerelease: false
41
+ requirement: &id003 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ version: 1.3.0
47
+ type: :development
48
+ version_requirements: *id003
49
+ description: Uses the last.fm api to analyse your scrobbles library and extracts the artists out in order of number of scrobbles
50
+ email:
51
+ - paulsturgess@gmail.com
52
+ executables: []
53
+
54
+ extensions: []
55
+
56
+ extra_rdoc_files: []
57
+
58
+ files:
59
+ - .gitignore
60
+ - .rspec
61
+ - Gemfile
62
+ - README.rdoc
63
+ - Rakefile
64
+ - lib/mostscrobbled.rb
65
+ - lib/mostscrobbled/artist.rb
66
+ - lib/mostscrobbled/last_fm.rb
67
+ - lib/mostscrobbled/version.rb
68
+ - mostscrobbled.gemspec
69
+ - spec/artist_spec.rb
70
+ - spec/fixtures/artists_failed.xml
71
+ - spec/fixtures/artists_ok.xml
72
+ - spec/last_fm_spec.rb
73
+ - spec/most_scrobbled_spec.rb
74
+ - spec/spec_helper.rb
75
+ has_rdoc: true
76
+ homepage: ""
77
+ licenses: []
78
+
79
+ post_install_message:
80
+ rdoc_options: []
81
+
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: "0"
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ none: false
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: "0"
96
+ requirements: []
97
+
98
+ rubyforge_project: mostscrobbled
99
+ rubygems_version: 1.6.2
100
+ signing_key:
101
+ specification_version: 3
102
+ summary: Extracts your most scrobbled artists from last.fm and turns them into nice ruby objects
103
+ test_files:
104
+ - spec/artist_spec.rb
105
+ - spec/fixtures/artists_failed.xml
106
+ - spec/fixtures/artists_ok.xml
107
+ - spec/last_fm_spec.rb
108
+ - spec/most_scrobbled_spec.rb
109
+ - spec/spec_helper.rb