grooveshark 0.1.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/lib/grooveshark.rb +10 -0
- data/lib/grooveshark/client.rb +84 -0
- data/lib/grooveshark/errors.rb +4 -0
- data/lib/grooveshark/playlist.rb +44 -0
- data/lib/grooveshark/request.rb +46 -0
- data/lib/grooveshark/song.rb +40 -0
- data/lib/grooveshark/user.rb +87 -0
- metadata +104 -0
data/lib/grooveshark.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
module Grooveshark
|
2
|
+
class Client
|
3
|
+
include Grooveshark::Request
|
4
|
+
|
5
|
+
attr_accessor :session, :comm_token
|
6
|
+
attr_reader :user
|
7
|
+
|
8
|
+
def initialize(session=nil)
|
9
|
+
@session = session || get_session
|
10
|
+
get_comm_token
|
11
|
+
end
|
12
|
+
|
13
|
+
# Obtain new session from Grooveshark
|
14
|
+
def get_session
|
15
|
+
resp = RestClient.get('http://listen.grooveshark.com')
|
16
|
+
resp.headers[:set_cookie].to_s.scan(/PHPSESSID=([a-z\d]{32});/i).flatten.first
|
17
|
+
end
|
18
|
+
|
19
|
+
# Get communication token
|
20
|
+
def get_comm_token
|
21
|
+
puts "Grooveshark::Client.get_comm_token"
|
22
|
+
@comm_token = nil # so that it doesn't send a token
|
23
|
+
@comm_token = request('getCommunicationToken', {:secretKey => Digest::MD5.hexdigest(@session)}, true)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Sign method
|
27
|
+
def create_token(method)
|
28
|
+
rnd = rand(256**3).to_s(16).rjust(6, '0')
|
29
|
+
plain = [method, @comm_token, 'quitStealinMahShit', rnd].join(':')
|
30
|
+
hash = Digest::SHA1.hexdigest(plain)
|
31
|
+
"#{rnd}#{hash}"
|
32
|
+
end
|
33
|
+
|
34
|
+
# Authenticate user
|
35
|
+
def login(user, password)
|
36
|
+
data = request('authenticateUser', {:username => user, :password => password}, true)
|
37
|
+
@user = User.new(self, data)
|
38
|
+
raise InvalidAuthentication, 'Wrong username or password!' if @user.id == 0
|
39
|
+
return @user
|
40
|
+
end
|
41
|
+
|
42
|
+
# Perform search request for query
|
43
|
+
def search(type, query)
|
44
|
+
results = request('getSearchResults', {:type => type, :query => query})
|
45
|
+
results.map { |song| Song.new song }
|
46
|
+
end
|
47
|
+
|
48
|
+
# Perform songs search request for query
|
49
|
+
def search_songs(query)
|
50
|
+
search('Songs', query)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Return raw response for songs search request
|
54
|
+
def search_songs_pure(query)
|
55
|
+
request('getSearchResultsEx', {:type => 'Songs', :query => query})
|
56
|
+
end
|
57
|
+
|
58
|
+
# Get stream authentication by song ID
|
59
|
+
def get_stream_auth_by_songid(song_id)
|
60
|
+
request('getStreamKeyFromSongIDEx', {
|
61
|
+
'songID' => song_id,
|
62
|
+
'prefetch' => false,
|
63
|
+
'mobile' => false,
|
64
|
+
'country' => COUNTRY
|
65
|
+
})
|
66
|
+
end
|
67
|
+
|
68
|
+
# Get stream authentication for song object
|
69
|
+
def get_stream_auth(song)
|
70
|
+
get_stream_auth_by_songid(song.id)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Get song stream url by ID
|
74
|
+
def get_song_url_by_id(id)
|
75
|
+
resp = get_stream_auth_by_songid(id)
|
76
|
+
"http://#{resp['ip']}/stream.php?streamKey=#{resp['streamKey']}"
|
77
|
+
end
|
78
|
+
|
79
|
+
# Get song stream
|
80
|
+
def get_song_url(song)
|
81
|
+
get_song_url_by_id(song.id)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Grooveshark
|
2
|
+
class Playlist
|
3
|
+
attr_reader :id, :user_id
|
4
|
+
attr_reader :name, :about, :picture, :username
|
5
|
+
attr_reader :songs
|
6
|
+
|
7
|
+
def initialize(client, data=nil, user_id=nil)
|
8
|
+
@client = client
|
9
|
+
@songs = []
|
10
|
+
|
11
|
+
if data
|
12
|
+
@id = data['PlaylistID']
|
13
|
+
@name = data['Name']
|
14
|
+
@about = data['About']
|
15
|
+
@picture = data['Picture']
|
16
|
+
@user_id = data['UserID'] || user_id
|
17
|
+
@username = data['Username']
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Fetch playlist songs
|
22
|
+
def load_songs
|
23
|
+
@songs = @client.request('playlistGetSongs', :playlistID => @id)['Songs']
|
24
|
+
@songs.map! { |s| Song.new(s) }
|
25
|
+
end
|
26
|
+
|
27
|
+
# Rename playlist
|
28
|
+
def rename(name, description)
|
29
|
+
begin
|
30
|
+
@client.request('renamePlaylist', :playlistID => @id, :playlistName => name)
|
31
|
+
@client.request('setPlaylistAbout', :playlistID => @id, :about => description)
|
32
|
+
@name = name ; @about = description
|
33
|
+
return true
|
34
|
+
rescue
|
35
|
+
return false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Delete existing playlist
|
40
|
+
def delete
|
41
|
+
@client.request('deletePlaylist', {:playlistID => @id, :name => @name})
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Grooveshark
|
2
|
+
module Request
|
3
|
+
API_BASE = 'cowbell.grooveshark.com'
|
4
|
+
UUID = 'E2AB1A59-C6B7-480E-992A-55DE1699D7F8'
|
5
|
+
CLIENT = 'htmlshark'
|
6
|
+
CLIENT_REV = '20101012.37'
|
7
|
+
COUNTRY = {"CC2" => "0","IPR" => "1","CC1" => "0","ID" => "1","CC4" => "0","CC3" => "0"}
|
8
|
+
|
9
|
+
# Client overrides for different methods
|
10
|
+
METHOD_CLIENTS = {
|
11
|
+
'getStreamKeyFromSongIDEx' => 'jsqueue'
|
12
|
+
}
|
13
|
+
|
14
|
+
# Perform API request
|
15
|
+
def request(method, params, secure=false)
|
16
|
+
agent = METHOD_CLIENTS.key?(method) ? METHOD_CLIENTS[method] : CLIENT
|
17
|
+
url = "#{secure ? 'https' : 'http'}://#{API_BASE}/more.php?#{method}"
|
18
|
+
body = {
|
19
|
+
'header' => {
|
20
|
+
'session' => @session,
|
21
|
+
'uuid' => UUID,
|
22
|
+
'client' => agent,
|
23
|
+
'clientRevision' => CLIENT_REV,
|
24
|
+
'country' => COUNTRY
|
25
|
+
},
|
26
|
+
'method' => method,
|
27
|
+
'parameters' => params
|
28
|
+
}
|
29
|
+
body['header']['token'] = create_token(method) if @comm_token
|
30
|
+
|
31
|
+
begin
|
32
|
+
data = RestClient.post(
|
33
|
+
url, body.to_json,
|
34
|
+
:content_type => :json,
|
35
|
+
:accept => :json,
|
36
|
+
:cookie => "PHPSESSID=#{@session}"
|
37
|
+
)
|
38
|
+
rescue Exception => ex
|
39
|
+
raise GeneralError # Need define error handling
|
40
|
+
end
|
41
|
+
|
42
|
+
data = JSON.parse(data)
|
43
|
+
return data['result'] unless data['fault']
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Grooveshark
|
2
|
+
class Song
|
3
|
+
attr_reader :data
|
4
|
+
attr_reader :id, :artist_id, :album_id
|
5
|
+
attr_reader :name, :artist, :album, :track
|
6
|
+
attr_reader :duraion, :artwork, :playcount
|
7
|
+
|
8
|
+
def initialize(data=nil)
|
9
|
+
unless data.nil?
|
10
|
+
@data = data
|
11
|
+
@id = data['SongID']
|
12
|
+
@name = data['SongName'] || data['Name']
|
13
|
+
@artist = data['ArtistName']
|
14
|
+
@artist_id = data['ArtistID']
|
15
|
+
@album = data['AlbumName']
|
16
|
+
@album_id = data['AlbumID']
|
17
|
+
@track = data['TrackNum']
|
18
|
+
@duration = data['EstimateDuration']
|
19
|
+
@artwork = data['CoverArtFilename']
|
20
|
+
@playcount = data['SongPlays']
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_s
|
25
|
+
[@id, @name, @artist].join(' - ')
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_hash
|
29
|
+
{
|
30
|
+
'songID' => @id,
|
31
|
+
'songName' => @name,
|
32
|
+
'artistName' => @artist,
|
33
|
+
'artistID' => @artist_id,
|
34
|
+
'albumName' => @album,
|
35
|
+
'albumID' => @album_id,
|
36
|
+
'track' => @track
|
37
|
+
}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Grooveshark
|
2
|
+
class User
|
3
|
+
attr_reader :id, :username, :premium, :data
|
4
|
+
attr_reader :playlists, :favorites
|
5
|
+
|
6
|
+
# Init user account object
|
7
|
+
def initialize(client, data=nil)
|
8
|
+
if data
|
9
|
+
@data = data
|
10
|
+
@id = data['userID']
|
11
|
+
@username = data['username']
|
12
|
+
@premium = data['isPremium']
|
13
|
+
end
|
14
|
+
@client = client
|
15
|
+
end
|
16
|
+
|
17
|
+
# --------------------------------------------------------------------------
|
18
|
+
# User Library
|
19
|
+
# --------------------------------------------------------------------------
|
20
|
+
|
21
|
+
# Fetch songs from library
|
22
|
+
def library(page=0)
|
23
|
+
resp = @client.request('userGetSongsInLibrary', {:userID => @id, :page => page.to_s})['Songs']
|
24
|
+
resp.map { |s| Song.new(s) }
|
25
|
+
end
|
26
|
+
|
27
|
+
# Add songs to user library (DOES NOT WORK FOR SOME REASON)
|
28
|
+
def library_add(songs=[])
|
29
|
+
@client.request('userAddSongsToLibrary', {:songs => songs.map { |s| s.to_hash }})
|
30
|
+
end
|
31
|
+
|
32
|
+
# Remove song from user library
|
33
|
+
def library_remove(song)
|
34
|
+
song_id = song.kind_of?(Song) ? song.id : song.to_s
|
35
|
+
@client.request('userRemoveSongFromLibrary', {:userID => @id, :songID => song_id})
|
36
|
+
end
|
37
|
+
|
38
|
+
# --------------------------------------------------------------------------
|
39
|
+
# User Playlists
|
40
|
+
# --------------------------------------------------------------------------
|
41
|
+
|
42
|
+
# Fetch user playlists
|
43
|
+
def playlists
|
44
|
+
return @playlists if @playlists
|
45
|
+
results = @client.request('userGetPlaylists', :userID => @id)
|
46
|
+
@playlists = results['Playlists'].map { |list| Playlist.new(@client, list, @id) }
|
47
|
+
end
|
48
|
+
|
49
|
+
# Get playlist by ID
|
50
|
+
def get_playlist(id)
|
51
|
+
result = playlists.select { |p| p.id == id }
|
52
|
+
result.nil? ? nil : result.first
|
53
|
+
end
|
54
|
+
|
55
|
+
# Create new user playlist
|
56
|
+
def create_playlist(name, description='', songs=[])
|
57
|
+
@client.request('createPlaylist', {
|
58
|
+
'playlistName' => name,
|
59
|
+
'playlistAbout' => description,
|
60
|
+
'songIDs' => songs.map { |s| s.kind_of?(Song) ? s.id : s.to_s }
|
61
|
+
})
|
62
|
+
end
|
63
|
+
|
64
|
+
# --------------------------------------------------------------------------
|
65
|
+
# User Favorites
|
66
|
+
# --------------------------------------------------------------------------
|
67
|
+
|
68
|
+
# Get user favorites
|
69
|
+
def favorites
|
70
|
+
return @favorites if @favorites
|
71
|
+
resp = @client.request('getFavorites', :ofWhat => 'Songs', :userID => @id)
|
72
|
+
@favorites = resp.map { |s| Song.new(s) }
|
73
|
+
end
|
74
|
+
|
75
|
+
# Add song to favorites
|
76
|
+
def add_favorite(song)
|
77
|
+
song_id = song.kind_of?(Song) ? song.id : song
|
78
|
+
@client.request('favorite', {:what => 'Song', :ID => song_id})
|
79
|
+
end
|
80
|
+
|
81
|
+
# Remove song from favorites
|
82
|
+
def remove_favorite(song)
|
83
|
+
song_id = song.kind_of?(Song) ? song.id : song
|
84
|
+
@client.request('unfavorite', {:what => 'Song', :ID => song_id})
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
metadata
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: grooveshark
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 25
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 1
|
10
|
+
version: 0.1.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Dan Sosedoff
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-01-08 00:00:00 -06:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: json
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 11
|
30
|
+
segments:
|
31
|
+
- 1
|
32
|
+
- 4
|
33
|
+
- 6
|
34
|
+
version: 1.4.6
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: rest-client
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 1
|
46
|
+
segments:
|
47
|
+
- 1
|
48
|
+
- 5
|
49
|
+
- 1
|
50
|
+
version: 1.5.1
|
51
|
+
type: :runtime
|
52
|
+
version_requirements: *id002
|
53
|
+
description: Unofficial ruby library for consuming the Grooveshark API.
|
54
|
+
email: dan.sosedoff@gmail.com
|
55
|
+
executables: []
|
56
|
+
|
57
|
+
extensions: []
|
58
|
+
|
59
|
+
extra_rdoc_files: []
|
60
|
+
|
61
|
+
files:
|
62
|
+
- lib/grooveshark.rb
|
63
|
+
- lib/grooveshark/client.rb
|
64
|
+
- lib/grooveshark/errors.rb
|
65
|
+
- lib/grooveshark/playlist.rb
|
66
|
+
- lib/grooveshark/request.rb
|
67
|
+
- lib/grooveshark/song.rb
|
68
|
+
- lib/grooveshark/user.rb
|
69
|
+
has_rdoc: true
|
70
|
+
homepage: http://github.com/sosedoff/grooveshark
|
71
|
+
licenses: []
|
72
|
+
|
73
|
+
post_install_message:
|
74
|
+
rdoc_options: []
|
75
|
+
|
76
|
+
require_paths:
|
77
|
+
- lib
|
78
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
79
|
+
none: false
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
hash: 3
|
84
|
+
segments:
|
85
|
+
- 0
|
86
|
+
version: "0"
|
87
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
88
|
+
none: false
|
89
|
+
requirements:
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
hash: 3
|
93
|
+
segments:
|
94
|
+
- 0
|
95
|
+
version: "0"
|
96
|
+
requirements: []
|
97
|
+
|
98
|
+
rubyforge_project:
|
99
|
+
rubygems_version: 1.4.1
|
100
|
+
signing_key:
|
101
|
+
specification_version: 3
|
102
|
+
summary: Grooveshark API
|
103
|
+
test_files: []
|
104
|
+
|