grooveshark 0.2.7 → 0.2.8
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.
- checksums.yaml +15 -0
- data/Gemfile +1 -1
- data/LICENSE +18 -0
- data/grooveshark.gemspec +2 -2
- data/lib/grooveshark.rb +0 -1
- data/lib/grooveshark/client.rb +72 -39
- data/lib/grooveshark/version.rb +1 -1
- data/spec/client_spec.rb +15 -1
- metadata +11 -30
- data/lib/grooveshark/request.rb +0 -63
- data/spec/request_spec.rb +0 -25
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
M2I1MWRjYjA2NTQyNzY4OTBmN2UwN2NjZGI4YmEwNjlmNDNhZGM4OA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
ZjU4YzQzNmU0MmM1NGY3Y2U3ZTY5YTFjYzljZWI5YjFlYWM3MmQwYw==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NjQ3MjlkMGI3ODNhNjk2NGNmNjEzYjFjZDkxNjdkMDE1ZmEzZDFlNjRiNjlk
|
10
|
+
OTZiNGViOTIwOWY0YmQ4OGNmMjdmZGJkOTJhY2I5M2U2ZGRkYjQzNTQ2MDI4
|
11
|
+
ODE5MmFmMWY3YzhkZWJlYjQ0YTBmMDBkYzJkOGM5ZjIxMTA1MjM=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
NGY3MjZlNzQ1ZTkzYzAyYjc2MjAyNjM2MjYxMjgyNGVmNmVlZDBhNDNiN2Qx
|
14
|
+
YWI0MDBkMDM3YmJkMmMwZDRjMjAzNTM5NDc4YjAwMGZkNzJjMzBjMGFmODhi
|
15
|
+
MDVlNTBkZmYyZTIwOTQ2NjlhMzEzMDBiZTNjNDg3ZTE2OWRjNjg=
|
data/Gemfile
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
source
|
1
|
+
source 'https://rubygems.org'
|
2
2
|
gemspec
|
data/LICENSE
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Copyright (c) 2011-2013 Dan Sosedoff.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
4
|
+
this software and associated documentation files (the "Software"), to deal in
|
5
|
+
the Software without restriction, including without limitation the rights to
|
6
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
7
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
8
|
+
subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
15
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
16
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
17
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
18
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/grooveshark.gemspec
CHANGED
@@ -15,8 +15,8 @@ Gem::Specification.new do |s|
|
|
15
15
|
s.executables = `git ls-files -- bin/*`.split("\n").map{|f| File.basename(f)}
|
16
16
|
s.require_paths = ['lib']
|
17
17
|
|
18
|
-
s.add_development_dependency 'rspec', '~> 2.
|
19
|
-
s.add_development_dependency 'rake', '~> 0
|
18
|
+
s.add_development_dependency 'rspec', '~> 2.12'
|
19
|
+
s.add_development_dependency 'rake', '~> 10.0'
|
20
20
|
|
21
21
|
s.add_runtime_dependency 'json', '>= 1.4.6'
|
22
22
|
s.add_runtime_dependency 'rest-client', '>= 1.5.1'
|
data/lib/grooveshark.rb
CHANGED
data/lib/grooveshark/client.rb
CHANGED
@@ -1,50 +1,15 @@
|
|
1
1
|
module Grooveshark
|
2
2
|
class Client
|
3
|
-
include Grooveshark::Request
|
4
|
-
|
5
3
|
attr_accessor :session, :comm_token
|
6
4
|
attr_reader :user, :comm_token_ttl, :country
|
7
5
|
|
8
|
-
def initialize(
|
6
|
+
def initialize(params = {})
|
7
|
+
@ttl = params[:ttl] || 120 # 2 minutes
|
9
8
|
@session, @country = get_session_and_country
|
10
9
|
@uuid = UUID.new.generate.upcase
|
11
10
|
get_comm_token
|
12
11
|
end
|
13
12
|
|
14
|
-
protected
|
15
|
-
|
16
|
-
def get_session_and_country
|
17
|
-
response = RestClient.get('http://grooveshark.com')
|
18
|
-
session = response.headers[:set_cookie].to_s.scan(/PHPSESSID=([a-z\d]{32});/i).flatten.first
|
19
|
-
config_json = response.to_s.scan(/window.gsConfig = (\{.*?\});/).flatten.first
|
20
|
-
raise GeneralError, "gsConfig not found" if not config_json
|
21
|
-
config = JSON.parse(config_json)
|
22
|
-
[session, config['country']]
|
23
|
-
end
|
24
|
-
|
25
|
-
# Get communication token
|
26
|
-
def get_comm_token
|
27
|
-
@comm_token = nil # request() uses it
|
28
|
-
@comm_token = request('getCommunicationToken', {:secretKey => Digest::MD5.hexdigest(@session)}, true)
|
29
|
-
@comm_token_ttl = Time.now.to_i
|
30
|
-
end
|
31
|
-
|
32
|
-
# Sign method
|
33
|
-
def create_token(method)
|
34
|
-
rnd = get_random_hex_chars(6)
|
35
|
-
salt = get_method_salt(method)
|
36
|
-
plain = [method, @comm_token, salt, rnd].join(':')
|
37
|
-
hash = Digest::SHA1.hexdigest(plain)
|
38
|
-
"#{rnd}#{hash}"
|
39
|
-
end
|
40
|
-
|
41
|
-
def get_random_hex_chars(length)
|
42
|
-
chars = ('a'..'f').to_a | (0..9).to_a
|
43
|
-
(0...length).map { chars[rand(chars.length)] }.join
|
44
|
-
end
|
45
|
-
|
46
|
-
public
|
47
|
-
|
48
13
|
# Authenticate user
|
49
14
|
def login(user, password)
|
50
15
|
data = request('authenticateUser', {:username => user, :password => password}, true)
|
@@ -124,10 +89,78 @@ module Grooveshark
|
|
124
89
|
get_song_url_by_id(song.id)
|
125
90
|
end
|
126
91
|
|
92
|
+
protected
|
93
|
+
|
94
|
+
def get_session_and_country
|
95
|
+
response = RestClient.get('http://grooveshark.com')
|
96
|
+
session = response.headers[:set_cookie].to_s.scan(/PHPSESSID=([a-z\d]{32});/i).flatten.first
|
97
|
+
config_json = response.to_s.scan(/window.gsConfig = (\{.*?\});/).flatten.first
|
98
|
+
raise GeneralError, "gsConfig not found" if not config_json
|
99
|
+
config = JSON.parse(config_json)
|
100
|
+
[session, config['country']]
|
101
|
+
end
|
102
|
+
|
103
|
+
# Get communication token
|
104
|
+
def get_comm_token
|
105
|
+
@comm_token = nil # request() uses it
|
106
|
+
@comm_token = request('getCommunicationToken', {:secretKey => Digest::MD5.hexdigest(@session)}, true)
|
107
|
+
@comm_token_ttl = Time.now.to_i
|
108
|
+
end
|
109
|
+
|
110
|
+
# Sign method
|
111
|
+
def create_token(method)
|
112
|
+
rnd = get_random_hex_chars(6)
|
113
|
+
salt = 'gooeyFlubber'
|
114
|
+
plain = [method, @comm_token, salt, rnd].join(':')
|
115
|
+
hash = Digest::SHA1.hexdigest(plain)
|
116
|
+
"#{rnd}#{hash}"
|
117
|
+
end
|
118
|
+
|
119
|
+
def get_random_hex_chars(length)
|
120
|
+
chars = ('a'..'f').to_a | (0..9).to_a
|
121
|
+
(0...length).map { chars[rand(chars.length)] }.join
|
122
|
+
end
|
123
|
+
|
127
124
|
private
|
128
125
|
|
129
|
-
|
130
|
-
|
126
|
+
# Perform API request
|
127
|
+
def request(method, params={}, secure=false)
|
128
|
+
refresh_token if @comm_token
|
129
|
+
|
130
|
+
url = "#{secure ? 'https' : 'http'}://grooveshark.com/more.php?#{method}"
|
131
|
+
body = {
|
132
|
+
'header' => {
|
133
|
+
'client' => 'mobileshark',
|
134
|
+
'clientRevision' => '20120830',
|
135
|
+
'country' => @country,
|
136
|
+
'privacy' => 0,
|
137
|
+
'session' => @session,
|
138
|
+
'uuid' => @uuid
|
139
|
+
},
|
140
|
+
'method' => method,
|
141
|
+
'parameters' => params
|
142
|
+
}
|
143
|
+
body['header']['token'] = create_token(method) if @comm_token
|
144
|
+
|
145
|
+
begin
|
146
|
+
data = RestClient.post(url, body.to_json, {'Content-Type' => 'application/json'})
|
147
|
+
rescue Exception => ex
|
148
|
+
raise GeneralError, ex.message
|
149
|
+
end
|
150
|
+
|
151
|
+
data = JSON.parse(data)
|
152
|
+
data = data.normalize if data.kind_of?(Hash)
|
153
|
+
|
154
|
+
if data.key?('fault')
|
155
|
+
raise ApiError.new(data['fault'])
|
156
|
+
else
|
157
|
+
data['result']
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
# Refresh communications token on ttl
|
162
|
+
def refresh_token
|
163
|
+
get_comm_token if Time.now.to_i - @comm_token_ttl > @ttl
|
131
164
|
end
|
132
165
|
end
|
133
166
|
end
|
data/lib/grooveshark/version.rb
CHANGED
data/spec/client_spec.rb
CHANGED
@@ -26,6 +26,20 @@ describe 'Client' do
|
|
26
26
|
@gs = Grooveshark::Client.new
|
27
27
|
lambda { @gs.login('invlid_user_name', 'invalid_password') }.should raise_error Grooveshark::InvalidAuthentication
|
28
28
|
end
|
29
|
+
|
30
|
+
it 'should obtain a new communication token on TTL expiration' do
|
31
|
+
@gs = Grooveshark::Client.new(:ttl => 1)
|
32
|
+
@tokens = []
|
33
|
+
|
34
|
+
3.times do |i|
|
35
|
+
@gs.search_songs('Muse')
|
36
|
+
@tokens << @gs.comm_token
|
37
|
+
sleep 3
|
38
|
+
end
|
39
|
+
|
40
|
+
@tokens.uniq!
|
41
|
+
@tokens.size.should == 3
|
42
|
+
end
|
29
43
|
end
|
30
44
|
|
31
45
|
context 'search' do
|
@@ -49,7 +63,7 @@ describe 'Client' do
|
|
49
63
|
context 'download' do
|
50
64
|
it 'should download without being banned' do
|
51
65
|
gs = Grooveshark::Client.new
|
52
|
-
ten_minutes_later = Time.new + 15 * 60 # Usually IP is banned after about
|
66
|
+
ten_minutes_later = Time.new + 15 * 60 # Usually IP is banned after about 15 minutes
|
53
67
|
while Time.new < ten_minutes_later do
|
54
68
|
# Try with a short song (this one is about a minute long)
|
55
69
|
song = gs.search_songs("Alan Reeves The Chase").first
|
metadata
CHANGED
@@ -1,52 +1,46 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: grooveshark
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
5
|
-
prerelease:
|
4
|
+
version: 0.2.8
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Dan Sosedoff
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2013-
|
11
|
+
date: 2013-06-10 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: rspec
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
17
|
- - ~>
|
20
18
|
- !ruby/object:Gem::Version
|
21
|
-
version: '2.
|
19
|
+
version: '2.12'
|
22
20
|
type: :development
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
24
|
- - ~>
|
28
25
|
- !ruby/object:Gem::Version
|
29
|
-
version: '2.
|
26
|
+
version: '2.12'
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: rake
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
31
|
- - ~>
|
36
32
|
- !ruby/object:Gem::Version
|
37
|
-
version: '0
|
33
|
+
version: '10.0'
|
38
34
|
type: :development
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
38
|
- - ~>
|
44
39
|
- !ruby/object:Gem::Version
|
45
|
-
version: '0
|
40
|
+
version: '10.0'
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: json
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
45
|
- - ! '>='
|
52
46
|
- !ruby/object:Gem::Version
|
@@ -54,7 +48,6 @@ dependencies:
|
|
54
48
|
type: :runtime
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
52
|
- - ! '>='
|
60
53
|
- !ruby/object:Gem::Version
|
@@ -62,7 +55,6 @@ dependencies:
|
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
56
|
name: rest-client
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
58
|
requirements:
|
67
59
|
- - ! '>='
|
68
60
|
- !ruby/object:Gem::Version
|
@@ -70,7 +62,6 @@ dependencies:
|
|
70
62
|
type: :runtime
|
71
63
|
prerelease: false
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
65
|
requirements:
|
75
66
|
- - ! '>='
|
76
67
|
- !ruby/object:Gem::Version
|
@@ -78,7 +69,6 @@ dependencies:
|
|
78
69
|
- !ruby/object:Gem::Dependency
|
79
70
|
name: uuid
|
80
71
|
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
72
|
requirements:
|
83
73
|
- - ~>
|
84
74
|
- !ruby/object:Gem::Version
|
@@ -86,7 +76,6 @@ dependencies:
|
|
86
76
|
type: :runtime
|
87
77
|
prerelease: false
|
88
78
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
79
|
requirements:
|
91
80
|
- - ~>
|
92
81
|
- !ruby/object:Gem::Version
|
@@ -100,6 +89,7 @@ files:
|
|
100
89
|
- .gitignore
|
101
90
|
- .rspec
|
102
91
|
- Gemfile
|
92
|
+
- LICENSE
|
103
93
|
- README.rdoc
|
104
94
|
- Rakefile
|
105
95
|
- grooveshark.gemspec
|
@@ -107,47 +97,38 @@ files:
|
|
107
97
|
- lib/grooveshark/client.rb
|
108
98
|
- lib/grooveshark/errors.rb
|
109
99
|
- lib/grooveshark/playlist.rb
|
110
|
-
- lib/grooveshark/request.rb
|
111
100
|
- lib/grooveshark/song.rb
|
112
101
|
- lib/grooveshark/user.rb
|
113
102
|
- lib/grooveshark/utils.rb
|
114
103
|
- lib/grooveshark/version.rb
|
115
104
|
- spec/client_spec.rb
|
116
105
|
- spec/helper.rb
|
117
|
-
- spec/request_spec.rb
|
118
106
|
- spec/utils_spec.rb
|
119
107
|
homepage: http://github.com/sosedoff/grooveshark
|
120
108
|
licenses: []
|
109
|
+
metadata: {}
|
121
110
|
post_install_message:
|
122
111
|
rdoc_options: []
|
123
112
|
require_paths:
|
124
113
|
- lib
|
125
114
|
required_ruby_version: !ruby/object:Gem::Requirement
|
126
|
-
none: false
|
127
115
|
requirements:
|
128
116
|
- - ! '>='
|
129
117
|
- !ruby/object:Gem::Version
|
130
118
|
version: '0'
|
131
|
-
segments:
|
132
|
-
- 0
|
133
|
-
hash: 504227010873878309
|
134
119
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
135
|
-
none: false
|
136
120
|
requirements:
|
137
121
|
- - ! '>='
|
138
122
|
- !ruby/object:Gem::Version
|
139
123
|
version: '0'
|
140
|
-
segments:
|
141
|
-
- 0
|
142
|
-
hash: 504227010873878309
|
143
124
|
requirements: []
|
144
125
|
rubyforge_project:
|
145
|
-
rubygems_version:
|
126
|
+
rubygems_version: 2.0.3
|
146
127
|
signing_key:
|
147
|
-
specification_version:
|
128
|
+
specification_version: 4
|
148
129
|
summary: Grooveshark API
|
149
130
|
test_files:
|
150
131
|
- spec/client_spec.rb
|
151
132
|
- spec/helper.rb
|
152
|
-
- spec/request_spec.rb
|
153
133
|
- spec/utils_spec.rb
|
134
|
+
has_rdoc:
|
data/lib/grooveshark/request.rb
DELETED
@@ -1,63 +0,0 @@
|
|
1
|
-
module Grooveshark
|
2
|
-
module Request
|
3
|
-
TOKEN_TTL = 120 # 2 minutes
|
4
|
-
|
5
|
-
# Perform API request
|
6
|
-
def request(method, params={}, secure=false)
|
7
|
-
refresh_token if @comm_token
|
8
|
-
|
9
|
-
url = "#{secure ? 'https' : 'http'}://grooveshark.com/more.php?#{method}"
|
10
|
-
body = {
|
11
|
-
'header' => {
|
12
|
-
'client' => get_method_client(method),
|
13
|
-
'clientRevision' => get_method_client_revision(method),
|
14
|
-
'country' => @country,
|
15
|
-
'privacy' => 0,
|
16
|
-
'session' => @session,
|
17
|
-
'uuid' => @uuid
|
18
|
-
},
|
19
|
-
'method' => method,
|
20
|
-
'parameters' => params
|
21
|
-
}
|
22
|
-
body['header']['token'] = create_token(method) if @comm_token
|
23
|
-
|
24
|
-
begin
|
25
|
-
data = RestClient.post(url, body.to_json, {'Content-Type' => 'application/json'})
|
26
|
-
rescue Exception => ex
|
27
|
-
raise GeneralError, ex.message
|
28
|
-
end
|
29
|
-
|
30
|
-
data = JSON.parse(data)
|
31
|
-
data = data.normalize if data.kind_of?(Hash)
|
32
|
-
|
33
|
-
if data.key?('fault')
|
34
|
-
raise ApiError.new(data['fault'])
|
35
|
-
else
|
36
|
-
data['result']
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
# Refresh communications token on ttl
|
41
|
-
def refresh_token
|
42
|
-
get_comm_token if Time.now.to_i - @comm_token_ttl > TOKEN_TTL
|
43
|
-
end
|
44
|
-
|
45
|
-
private
|
46
|
-
|
47
|
-
def get_method_client(method)
|
48
|
-
jsqueue_methods = [
|
49
|
-
'getStreamKeyFromSongIDEx',
|
50
|
-
'addSongsToQueue',
|
51
|
-
'markSongDownloadedEx',
|
52
|
-
'markStreamKeyOver30Seconds',
|
53
|
-
'markSongQueueSongPlayed',
|
54
|
-
'markSongComplete'
|
55
|
-
]
|
56
|
-
jsqueue_methods.include?(method) ? 'jsqueue' : 'htmlshark'
|
57
|
-
end
|
58
|
-
|
59
|
-
def get_method_client_revision(method)
|
60
|
-
get_method_client(method) == 'jsqueue' ? '20120312.02' : '20120312'
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
data/spec/request_spec.rb
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
require File.expand_path("./helper", File.dirname(__FILE__))
|
2
|
-
|
3
|
-
describe 'Request' do
|
4
|
-
module Grooveshark
|
5
|
-
module Request
|
6
|
-
# Override default ttl for tests
|
7
|
-
remove_const :TOKEN_TTL # Avoid the "already initialized constant" warning
|
8
|
-
TOKEN_TTL = 1
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
# it 'should obtain a new communication token on TTL expiration' do
|
13
|
-
# @gs = Grooveshark::Client.new
|
14
|
-
# @tokens = []
|
15
|
-
#
|
16
|
-
# 3.times do |i|
|
17
|
-
# @gs.search_songs('Muse')
|
18
|
-
# @tokens << @gs.comm_token
|
19
|
-
# sleep 3
|
20
|
-
# end
|
21
|
-
#
|
22
|
-
# @tokens.uniq!
|
23
|
-
# @tokens.size.should == 3
|
24
|
-
# end
|
25
|
-
end
|