Skip to content

Commit

Permalink
Added support for scrobbling and now playing submission
Browse files Browse the repository at this point in the history
  • Loading branch information
titanous committed Sep 16, 2008
1 parent 096ef68 commit 2ab0827
Show file tree
Hide file tree
Showing 4 changed files with 206 additions and 0 deletions.
32 changes: 32 additions & 0 deletions examples/scrobble.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
require 'rubygems'
require 'scrobbler'

auth = Scrobbler::SimpleAuth.new(:user => 'chunky', :password => 'bacon')
auth.handshake!

puts "Auth Status: #{auth.status}"
puts "Session ID: #{auth.session_id}"
puts "Now Playing URL: #{auth.now_playing_url}"
puts "Submission URL: #{auth.submission_url}"

scrobble = Scrobbler::Scrobble.new(:session_id => auth.session_id,
:submission_url => auth.submission_url,
:artist => 'Coldplay',
:track => 'Viva La Vida',
:album => "Viva La Vida",
:time => Time.new,
:length => 244,
:track_number => 7)
scrobble.submit!
puts "Scrobbler Submission Status: #{scrobble.status}"

playing = Scrobbler::Playing.new(:session_id => auth.session_id,
:now_playing_url => auth.now_playing_url,
:artist => 'Anberlin',
:track => 'A Day Late',
:album => 'Never Take Friendship Personal',
:length => 214,
:track_number => 5)

playing.submit!
puts "Playing Submission Status: #{playing.status}"
49 changes: 49 additions & 0 deletions lib/scrobbler/playing.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
module Scrobbler
class Playing
# you should read last.fm/api/submissions#np first!

attr_accessor :session_id, :now_playing_url, :artist, :track,
:album, :length, :track_number, :mb_track_id
attr_reader :status

def initialize(args = {})
@session_id = args[:session_id] # from Scrobbler::SimpleAuth
@now_playing_url = args[:now_playing_url] # from Scrobbler::SimpleAuth (can change)
@artist = args[:artist] # track artist
@track = args[:track] # track name
@album = args[:album] || '' # track album (optional)
@length = args[:length] || '' # track length in seconds (optional)
@track_number = args[:track_number] || '' # track number (optional)
@mb_track_id = args[:mb_track_id] || '' # MusicBrainz track ID (optional)

if [@session_id, @now_playing_url, @artist, @track].any?(&:empty?)
raise ArgumentError, 'Missing required argument'
elsif !@length.to_s.empty? && @length.to_i <= 30 # see last.fm/api
raise ArgumentError, 'Length must be greater than 30 seconds'
end

@connection = REST::Connection.new(@now_playing_url)
end

def submit!
query = { :s => @session_id,
:a => @artist,
:t => @track,
:b => @album,
:l => @length,
:n => @track_number,
:m => @mb_track_id }

@status = @connection.post('', query)

case @status
when /OK/

when /BADSESSION/
raise BadSessionError # rerun Scrobbler::SimpleAuth#handshake!
else
raise RequestFailedError
end
end
end
end
66 changes: 66 additions & 0 deletions lib/scrobbler/scrobble.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# exception definitions
class BadSessionError < StandardError; end
class RequestFailedError < StandardError; end

module Scrobbler
class Scrobble
# you need to read last.fm/api/submissions#subs first!

attr_accessor :session_id, :submission_url, :artist, :track, :time,
:source, :length, :album, :track_number, :mb_track_id
attr_reader :status

def initialize(args = {})
@session_id = args[:session_id] # from Scrobbler::SimpleAuth
@submission_url = args[:submission_url] # from Scrobbler::SimpleAuth (can change)
@artist = args[:artist] # track artist
@track = args[:track] # track name
@time = args[:time] # a Time object set to the time the track started playing
@source = args[:source] || 'P' # track source, see last.fm/api/submissions#subs
@length = args[:length].to_s || '' # track length in seconds
@album = args[:album] || '' # track album name (optional)
@track_number = args[:track_number] || '' # track number (optional)
@mb_track_id = args[:mb_track_id] || '' # MusicBrainz track ID (optional)

if [@session_id, @submission_url, @artist, @track].any?(&:empty?)
raise ArgumentError, 'Missing required argument'
elsif @time.class.to_s != 'Time'
raise ArgumentError, ":time must be a Time object"
elsif !['P','R','E','U'].include?(@source) # see last.fm/api/submissions#subs
raise ArgumentError, "Invalid source"
elsif @source == 'P' && @length.empty? # length is not optional if source is P
raise ArgumentError, 'Length must be set'
elsif !@length.empty? && @length.to_i <= 30 # see last.fm/api/submissions#subs
raise ArgumentError, 'Length must be greater than 30 seconds'
end

@connection = REST::Connection.new(@submission_url)
end

def submit!
query = { :s => @session_id,
'a[0]' => @artist,
't[0]' => @track,
'i[0]' => @time.utc.to_i,
'o[0]' => @source,
'r[0]' => @rating,
'l[0]' => @length,
'b[0]' => @album,
'n[0]' => @track_number,
'm[0]' => @mb_track_id }

@status = @connection.post('', query)

case @status
when /OK/

when /BADSESSION/
raise BadSessionError # rerun Scrobbler::SimpleAuth#handshake!
when /FAILED/
raise RequestFailedError, @status
else
raise RequestFailedError
end
end
end
end
59 changes: 59 additions & 0 deletions lib/scrobbler/simpleauth.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
require 'digest/md5'

# exception definitions
class BadAuthError < StandardError; end
class BannedError < StandardError; end
class BadTimeError < StandardError; end
module Scrobbler
AUTH_URL = 'http://post.audioscrobbler.com'
AUTH_VER = '1.2.1'

class SimpleAuth
# you should read last.fm/api/submissions#handshake

attr_accessor :user, :password, :client_id, :client_ver
attr_reader :status, :session_id, :now_playing_url, :submission_url

def initialize(args = {})
@user = args[:user] # last.fm username
@password = args[:password] # last.fm password
@client_id = 'rbs' # Client ID assigned by last.fm; Don't change this!
@client_ver = Scrobbler::VERSION::STRING

raise ArgumentError, 'Missing required argument' if @user.blank? || @password.blank?

@connection = REST::Connection.new(AUTH_URL)
end

def handshake!
password_hash = Digest::MD5.hexdigest(@password)
timestamp = Time.now.to_i.to_s
token = Digest::MD5.hexdigest(password_hash + timestamp)

query = { :hs => 'true',
:p => AUTH_VER,
:c => @client_id,
:v => @client_ver,
:u => @user,
:t => timestamp,
:a => token }
result = @connection.get('/', query)

@status = result.split(/\n/)[0]
case @status
when /OK/
@session_id, @now_playing_url, @submission_url = result.split(/\n/)[1,3]
when /BANNED/
raise BannedError # something is wrong with the gem, check for an update
when /BADAUTH/
raise BadAuthError # invalid user/password
when /FAILED/
raise RequestFailedError, @status
when /BADTIME/
raise BadTimeError # system time is way off
else
raise RequestFailedError
end
end
end
end

0 comments on commit 2ab0827

Please sign in to comment.