lastfm12 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/History.txt +4 -0
- data/Manifest.txt +24 -0
- data/PostInstall.txt +7 -0
- data/README.rdoc +48 -0
- data/Rakefile +4 -0
- data/config/hoe.rb +77 -0
- data/config/requirements.rb +15 -0
- data/lib/lastfm12/version.rb +10 -0
- data/lib/lastfm12.rb +491 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +82 -0
- data/setup.rb +1585 -0
- data/tasks/deployment.rake +34 -0
- data/tasks/environment.rake +7 -0
- data/tasks/website.rake +17 -0
- data/test/test_helper.rb +2 -0
- data/test/test_lastfm12.rb +12 -0
- data/website/index.html +117 -0
- data/website/index.txt +83 -0
- data/website/javascripts/rounded_corners_lite.inc.js +285 -0
- data/website/stylesheets/screen.css +138 -0
- data/website/template.html.erb +48 -0
- metadata +99 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
PostInstall.txt
|
4
|
+
README.rdoc
|
5
|
+
Rakefile
|
6
|
+
config/hoe.rb
|
7
|
+
config/requirements.rb
|
8
|
+
lib/lastfm12.rb
|
9
|
+
lib/lastfm12/version.rb
|
10
|
+
script/console
|
11
|
+
script/destroy
|
12
|
+
script/generate
|
13
|
+
script/txt2html
|
14
|
+
setup.rb
|
15
|
+
tasks/deployment.rake
|
16
|
+
tasks/environment.rake
|
17
|
+
tasks/website.rake
|
18
|
+
test/test_helper.rb
|
19
|
+
test/test_lastfm12.rb
|
20
|
+
website/index.html
|
21
|
+
website/index.txt
|
22
|
+
website/javascripts/rounded_corners_lite.inc.js
|
23
|
+
website/stylesheets/screen.css
|
24
|
+
website/template.html.erb
|
data/PostInstall.txt
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
= lastfm12
|
2
|
+
|
3
|
+
* http://lastfm12.rubyforge.org/
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
FIX (describe your package)
|
8
|
+
|
9
|
+
== FEATURES/PROBLEMS:
|
10
|
+
|
11
|
+
* FIX (list of features or problems)
|
12
|
+
|
13
|
+
== SYNOPSIS:
|
14
|
+
|
15
|
+
FIX (code sample of usage)
|
16
|
+
|
17
|
+
== REQUIREMENTS:
|
18
|
+
|
19
|
+
* FIX (list of requirements)
|
20
|
+
|
21
|
+
== INSTALL:
|
22
|
+
|
23
|
+
* FIX (sudo gem install, anything else)
|
24
|
+
|
25
|
+
== LICENSE:
|
26
|
+
|
27
|
+
(The MIT License)
|
28
|
+
|
29
|
+
Copyright (c) 2008 FIXME full name
|
30
|
+
|
31
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
32
|
+
a copy of this software and associated documentation files (the
|
33
|
+
'Software'), to deal in the Software without restriction, including
|
34
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
35
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
36
|
+
permit persons to whom the Software is furnished to do so, subject to
|
37
|
+
the following conditions:
|
38
|
+
|
39
|
+
The above copyright notice and this permission notice shall be
|
40
|
+
included in all copies or substantial portions of the Software.
|
41
|
+
|
42
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
43
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
44
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
45
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
46
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
47
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
48
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
data/config/hoe.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'lastfm12/version'
|
2
|
+
|
3
|
+
AUTHOR = 'Keiichiro Ui' # can also be an array of Authors
|
4
|
+
EMAIL = "keiichiro.ui@gmail.com"
|
5
|
+
DESCRIPTION = "lastfm12 is a wrapper around the Last.fm protocol version 1.2. This library can manipulate the last.fm radio streams. So, you can implement easily the last.fm radio."
|
6
|
+
GEM_NAME = 'lastfm12' # what ppl will type to install your gem
|
7
|
+
RUBYFORGE_PROJECT = 'lastfm12' # The unix name for your project
|
8
|
+
HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
|
9
|
+
DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
|
10
|
+
EXTRA_DEPENDENCIES = [
|
11
|
+
# ['activesupport', '>= 1.3.1']
|
12
|
+
] # An array of rubygem dependencies [name, version]
|
13
|
+
EXTRA_DEV_DEPENDENCIES = [
|
14
|
+
# ['rspec', '>= 1.1.5']
|
15
|
+
] # An array of rubygem dependencies [name, version]
|
16
|
+
|
17
|
+
@config_file = "~/.rubyforge/user-config.yml"
|
18
|
+
@config = nil
|
19
|
+
RUBYFORGE_USERNAME = "kui"
|
20
|
+
def rubyforge_username
|
21
|
+
unless @config
|
22
|
+
begin
|
23
|
+
@config = YAML.load(File.read(File.expand_path(@config_file)))
|
24
|
+
rescue
|
25
|
+
puts <<-EOS
|
26
|
+
ERROR: No rubyforge config file found: #{@config_file}
|
27
|
+
Run 'rubyforge setup' to prepare your env for access to Rubyforge
|
28
|
+
- See http://newgem.rubyforge.org/rubyforge.html for more details
|
29
|
+
EOS
|
30
|
+
exit
|
31
|
+
end
|
32
|
+
end
|
33
|
+
RUBYFORGE_USERNAME.replace @config["username"]
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
REV = nil
|
38
|
+
# UNCOMMENT IF REQUIRED:
|
39
|
+
# REV = YAML.load(`svn info`)['Revision']
|
40
|
+
VERS = Lastfm12::VERSION::STRING + (REV ? ".#{REV}" : "")
|
41
|
+
RDOC_OPTS = ['--quiet', '--title', 'lastfm12 documentation',
|
42
|
+
"--opname", "index.html",
|
43
|
+
"--line-numbers",
|
44
|
+
"--main", "README",
|
45
|
+
"--inline-source"]
|
46
|
+
|
47
|
+
class Hoe
|
48
|
+
def extra_deps
|
49
|
+
@extra_deps.reject! { |x| Array(x).first == 'hoe' }
|
50
|
+
@extra_deps
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Generate all the Rake tasks
|
55
|
+
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
56
|
+
$hoe = Hoe.new(GEM_NAME, VERS) do |p|
|
57
|
+
p.developer(AUTHOR, EMAIL)
|
58
|
+
p.description = DESCRIPTION
|
59
|
+
p.summary = DESCRIPTION
|
60
|
+
p.url = HOMEPATH
|
61
|
+
p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
|
62
|
+
p.test_globs = ["test/**/test_*.rb"]
|
63
|
+
p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
|
64
|
+
|
65
|
+
# == Optional
|
66
|
+
p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
|
67
|
+
p.extra_deps = EXTRA_DEPENDENCIES
|
68
|
+
p.extra_dev_deps = EXTRA_DEV_DEPENDENCIES
|
69
|
+
|
70
|
+
p.spec_extras = {} # A hash of extra values to set in the gemspec.
|
71
|
+
end
|
72
|
+
|
73
|
+
CHANGES = $hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
|
74
|
+
PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
|
75
|
+
$hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
|
76
|
+
$hoe.rsync_args = '-av --delete --ignore-errors'
|
77
|
+
$hoe.spec.post_install_message = File.open(File.dirname(__FILE__) + "/../PostInstall.txt").read rescue ""
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
include FileUtils
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
%w[rake hoe newgem rubigen].each do |req_gem|
|
6
|
+
begin
|
7
|
+
require req_gem
|
8
|
+
rescue LoadError
|
9
|
+
puts "This Rakefile requires the '#{req_gem}' RubyGem."
|
10
|
+
puts "Installation: gem install #{req_gem} -y"
|
11
|
+
exit
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
$:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
|
data/lib/lastfm12.rb
ADDED
@@ -0,0 +1,491 @@
|
|
1
|
+
#
|
2
|
+
#=lastfm12
|
3
|
+
#
|
4
|
+
#Author:: {Keiichiro Ui}[http://k-ui.jp] (keiichiro.ui[at]gmail.com)
|
5
|
+
#Version:: 0.1
|
6
|
+
#License:: MIT License
|
7
|
+
#
|
8
|
+
#==Simplest Example
|
9
|
+
#
|
10
|
+
#Playing Queen's similar tracks with mpg123
|
11
|
+
#
|
12
|
+
# require "lastfm12"
|
13
|
+
# hash = {
|
14
|
+
# :user_name => "username",
|
15
|
+
# :password => "password",
|
16
|
+
# :station => ["artist", "queen"]
|
17
|
+
# }
|
18
|
+
# loop do
|
19
|
+
# LastFM12.get_tracks(hash).each do |t|
|
20
|
+
# `mpg123 #{t.location}`
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
#==Basic Example
|
25
|
+
#
|
26
|
+
#Downloading tracks tagged as "electoronic"
|
27
|
+
#
|
28
|
+
# require "lastfm12"
|
29
|
+
#
|
30
|
+
# lastfm = LastFM12.new("username", "password")
|
31
|
+
#
|
32
|
+
# # Adjusting the electoronic tag radio station
|
33
|
+
# lastfm.adjust_station("tag", "electoronic")
|
34
|
+
#
|
35
|
+
# # Downloading tracks
|
36
|
+
# loop do
|
37
|
+
# lastfm.get_tracks.each do |track|
|
38
|
+
# puts "-------------------------------------------"
|
39
|
+
# puts "artist: #{track.artist}"
|
40
|
+
# puts "title: #{track.title}"
|
41
|
+
# puts "album: #{track.album}"
|
42
|
+
# puts "length: #{track.length/1000}[sec]"
|
43
|
+
# `wget #{track.location}`
|
44
|
+
# end
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
#
|
48
|
+
#==Reference
|
49
|
+
#
|
50
|
+
#* {LastFM12UnofficialDocumentation}[http://code.google.com/p/thelastripper/wiki/LastFM12UnofficialDocumentation]
|
51
|
+
#
|
52
|
+
#==Change Log
|
53
|
+
#
|
54
|
+
#- Ver.0.1 Sun Oct 19 2008
|
55
|
+
# - Create lastfm12.rb
|
56
|
+
#
|
57
|
+
|
58
|
+
require "net/http"
|
59
|
+
require "uri"
|
60
|
+
require "cgi"
|
61
|
+
require "digest/md5"
|
62
|
+
require "rexml/document"
|
63
|
+
|
64
|
+
#main class
|
65
|
+
class LastFM12
|
66
|
+
|
67
|
+
HANDSHAKE_HOST='ws.audioscrobbler.com'
|
68
|
+
HANDSHAKE_PATH='/radio'
|
69
|
+
HANDSHAKE_SCRIPT='handshake.php'
|
70
|
+
ADJUST_SCRIPT='adjust.php'
|
71
|
+
PLAYLIST_SCRIPT='xspf.php'
|
72
|
+
|
73
|
+
DEFAULT_USER_AGENT='Ruby-Lastfm12'
|
74
|
+
|
75
|
+
#Handshake with ws.audioscrobbler.com
|
76
|
+
#[_username_]
|
77
|
+
# an account name on last.fm
|
78
|
+
#[_password_]
|
79
|
+
# an password for the account
|
80
|
+
#[_opt_]
|
81
|
+
# a hash as Fig.A
|
82
|
+
#
|
83
|
+
#===Fig.A
|
84
|
+
#_key_:: _value_
|
85
|
+
#:user_agent or "user_agent":: an string used as an user agent name for handshake, ajusting radio station and playlist requests
|
86
|
+
#:station or "staion":: an array of strings such as ["tag","electoro"]. refer _adjust_station_ method
|
87
|
+
#:verbose or "verbose":: true: output oparations, false: no output
|
88
|
+
|
89
|
+
def initialize(username,password,opt=nil)
|
90
|
+
|
91
|
+
@user_name = username.to_s
|
92
|
+
@password = password.to_s
|
93
|
+
|
94
|
+
@user_agent=DEFAULT_USER_AGENT
|
95
|
+
@station = nil
|
96
|
+
@verbose = $DEBUG
|
97
|
+
if opt.class == Hash
|
98
|
+
opt.each do |k,v|
|
99
|
+
case k
|
100
|
+
when "user_agent",:user_agent
|
101
|
+
@user_agent = v.to_s
|
102
|
+
when "station", :station
|
103
|
+
@station = _make_lastfm_url(*(v.to_a))
|
104
|
+
when "verbose", :verbose
|
105
|
+
@verbose = true
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
@session = nil
|
111
|
+
@base_url = nil
|
112
|
+
@base_path = nil
|
113
|
+
_handshake
|
114
|
+
|
115
|
+
if @station
|
116
|
+
_adjust_station(@station)
|
117
|
+
end
|
118
|
+
|
119
|
+
@@instance=self
|
120
|
+
|
121
|
+
end
|
122
|
+
attr_reader :user_name, :user_agent, :station, :verbose
|
123
|
+
|
124
|
+
#Adjusting a station specified as arguments
|
125
|
+
#===Arguments
|
126
|
+
#These argments class should be Symbol class or String class.
|
127
|
+
#_param_name_:: Discription
|
128
|
+
#personal:: _param_'s personal radio station
|
129
|
+
#artist:: _param_'s similar radio station
|
130
|
+
#tag or globaltags:: a radio station having tracks tagged as _param_
|
131
|
+
#group:: a radio statio for _param_ group
|
132
|
+
#neighbours:: _param_'s neighbours radio station
|
133
|
+
#recommended:: _param_'s recommended radio station
|
134
|
+
def adjust_station(param_name,param)
|
135
|
+
|
136
|
+
station = _make_lastfm_url(param_name, param)
|
137
|
+
|
138
|
+
if @station == station
|
139
|
+
puts "Already Adjusted The Station" if @verbose
|
140
|
+
return station
|
141
|
+
else
|
142
|
+
@station = station
|
143
|
+
end
|
144
|
+
|
145
|
+
_adjust_station(@station)
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
#Getting tracks
|
150
|
+
#Return a array of tracks.
|
151
|
+
#[_num_] the minimun number of tracks
|
152
|
+
#===Note
|
153
|
+
#The length of the returned array is vary. So, sometime, _get_tracks_ get no track.
|
154
|
+
#Give _min_num_tracks_, if you want to get tracks more than _min_num_tracks_.
|
155
|
+
def get_tracks(min_num_tracks=nil)
|
156
|
+
|
157
|
+
ret = []
|
158
|
+
count = 0
|
159
|
+
|
160
|
+
if min_num_tracks
|
161
|
+
|
162
|
+
while ret.length < min_num_tracks
|
163
|
+
|
164
|
+
ret = ret + _get_tracks
|
165
|
+
|
166
|
+
if @verbose
|
167
|
+
z = ret.length.zero?
|
168
|
+
puts "#{z ? '' : 'Success'} Getting #{z ? 'No' : ret.length } Tracks"
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
172
|
+
|
173
|
+
else
|
174
|
+
ret = _get_tracks
|
175
|
+
end
|
176
|
+
|
177
|
+
ret
|
178
|
+
|
179
|
+
end
|
180
|
+
|
181
|
+
def play_loop(&block)
|
182
|
+
|
183
|
+
loop do
|
184
|
+
self.get_tracks(1).each(&block)
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|
188
|
+
|
189
|
+
def LastFM12.play_loop(*args,&block)
|
190
|
+
|
191
|
+
if args.length == 1 and args[0].kind_of?(Hash)
|
192
|
+
hash = args[0]
|
193
|
+
elsif args.length == 3 and args[2].kind_of?(Hash)
|
194
|
+
hash = args[2]
|
195
|
+
hash[:user_name] = args[0]
|
196
|
+
hash[:password] = args[1]
|
197
|
+
end
|
198
|
+
|
199
|
+
new_hash = Hash.new
|
200
|
+
hash.each{|k,v|new_hash[k.to_sym]=new_hash[k.to_s]=v}
|
201
|
+
hash = new_hash
|
202
|
+
|
203
|
+
if @@instance.nil? or @@instance.user_name != hash[:user_name]
|
204
|
+
@@instance = LastFM12.new(hash[:user_name],hash[:password],hash)
|
205
|
+
else
|
206
|
+
puts "Skip Handshake" if @@instance.verbose
|
207
|
+
end
|
208
|
+
|
209
|
+
@@instance.play_loop(&block)
|
210
|
+
|
211
|
+
end
|
212
|
+
@@instance=nil
|
213
|
+
|
214
|
+
#a class for tracks
|
215
|
+
class Track
|
216
|
+
|
217
|
+
def initialize(hash)
|
218
|
+
if hash.class != Hash
|
219
|
+
raise ArgumentError
|
220
|
+
end
|
221
|
+
@hash = hash
|
222
|
+
end
|
223
|
+
|
224
|
+
def [](key)
|
225
|
+
@hash[key]
|
226
|
+
end
|
227
|
+
|
228
|
+
#A redirection URL to another URL
|
229
|
+
#* Cannot make multi-connetion with the URL.
|
230
|
+
#* Cannot make a connection after second with the URL.
|
231
|
+
def location
|
232
|
+
@hash[:location]
|
233
|
+
end
|
234
|
+
|
235
|
+
# a title of the track
|
236
|
+
def title
|
237
|
+
@hash[:title]
|
238
|
+
end
|
239
|
+
#alias _title_
|
240
|
+
def name
|
241
|
+
title
|
242
|
+
end
|
243
|
+
|
244
|
+
# a album name of the track
|
245
|
+
def album
|
246
|
+
@hash[:album]
|
247
|
+
end
|
248
|
+
|
249
|
+
# a creator name of the track
|
250
|
+
def creator
|
251
|
+
@hash[:creator]
|
252
|
+
end
|
253
|
+
# alias _creator_
|
254
|
+
def artist
|
255
|
+
creator
|
256
|
+
end
|
257
|
+
|
258
|
+
# seconds of the track
|
259
|
+
def duration
|
260
|
+
@hash[:duration].to_i
|
261
|
+
end
|
262
|
+
|
263
|
+
# alias _duration_
|
264
|
+
def length
|
265
|
+
duration
|
266
|
+
end
|
267
|
+
|
268
|
+
# an URL of the track image
|
269
|
+
def image_url
|
270
|
+
@hash[:image]
|
271
|
+
end
|
272
|
+
|
273
|
+
# a station name
|
274
|
+
def station
|
275
|
+
@hash[:station]
|
276
|
+
end
|
277
|
+
|
278
|
+
#execute a given block against the mp3 stream
|
279
|
+
#the block is given a segument data of mp3
|
280
|
+
def play(&block)
|
281
|
+
|
282
|
+
uri = URI(@hash[:location])
|
283
|
+
ret = nil
|
284
|
+
redirect_flag = true
|
285
|
+
|
286
|
+
while redirect_flag
|
287
|
+
|
288
|
+
host = uri.host
|
289
|
+
path = uri.path
|
290
|
+
path = path + "?" + uri.query if uri.query
|
291
|
+
redirect_flag = false
|
292
|
+
|
293
|
+
header = {
|
294
|
+
'Host' => host,
|
295
|
+
'User-Agent' => @hash[:user_agent],
|
296
|
+
}
|
297
|
+
Net::HTTP.new(host).request_get(path,header) do |res|
|
298
|
+
|
299
|
+
if res.code.match(/^30[0-3]$/)
|
300
|
+
uri = URI(res['location'])
|
301
|
+
redirect_flag = true
|
302
|
+
next
|
303
|
+
end
|
304
|
+
|
305
|
+
res.read_body(&block)
|
306
|
+
|
307
|
+
end
|
308
|
+
end # of "begin"
|
309
|
+
|
310
|
+
ret
|
311
|
+
|
312
|
+
end # of "def play(&block)"
|
313
|
+
|
314
|
+
|
315
|
+
end # of "class Track"
|
316
|
+
|
317
|
+
#General exception for Lastfm12
|
318
|
+
class Error < Exception; end
|
319
|
+
|
320
|
+
#Exception class for errors of handshake
|
321
|
+
class HandshakeError < Error; end
|
322
|
+
|
323
|
+
#Exception class for errors of adjusting radion station
|
324
|
+
#There ar 9 exception messages:
|
325
|
+
#* There is not enough content to play the station. Due to restrictions imposed by the music labels, a radio station must have more than 15 tracks; each by different artists.
|
326
|
+
#* The group does not have enough members to have a radio station.
|
327
|
+
#* The stream has stopped. Please try again later, or try another station.
|
328
|
+
#* The user does not have enough neighbors to have a radio station.
|
329
|
+
#* The station is available to subscribers only.
|
330
|
+
#* The station is not available for streaming.
|
331
|
+
#* The artist does not have enough fans to have a radio station.
|
332
|
+
#* An unknown error occurred.
|
333
|
+
#referred to on {adjust.php error codes}[http://www.lastfm.de/forum/21716/_/380495/1#f5829616]
|
334
|
+
class AdjustingError < Error;
|
335
|
+
Messages = ['There is not enough content to play the station. Due to restrictions imposed by the music labels, a radio station must have more than 15 tracks; each by different artists.',
|
336
|
+
'The group does not have enough members to have a radio station.',
|
337
|
+
'The artist does not have enough fans to have a radio station.',
|
338
|
+
'The station is not available for streaming.',
|
339
|
+
'The station is available to subscribers only.',
|
340
|
+
'The user does not have enough neighbors to have a radio station.',
|
341
|
+
'An unknown error occurred.']
|
342
|
+
end
|
343
|
+
|
344
|
+
#Exception class of getting tracks
|
345
|
+
class GettingTracksError < Error; end
|
346
|
+
|
347
|
+
private
|
348
|
+
|
349
|
+
def _handshake
|
350
|
+
|
351
|
+
ret = nil
|
352
|
+
|
353
|
+
h = {
|
354
|
+
'version' => '1.3.1.1',
|
355
|
+
'platform' => 'linux',
|
356
|
+
'username' => @user_name,
|
357
|
+
'passwordmd5' => Digest::MD5.hexdigest(@password),
|
358
|
+
}
|
359
|
+
query = _make_http_query(h)
|
360
|
+
path = "%s/%s?%s" % [HANDSHAKE_PATH,HANDSHAKE_SCRIPT,query]
|
361
|
+
header = {
|
362
|
+
'Host' => HANDSHAKE_HOST,
|
363
|
+
'User-Agent' => @user_agent,
|
364
|
+
}
|
365
|
+
Net::HTTP.new(HANDSHAKE_HOST).request_get(path,header) do |res|
|
366
|
+
#ph res
|
367
|
+
ret = Hash[*res.body.split("\n").map{|i|i.split('=',2)}.flatten]
|
368
|
+
#ph ret
|
369
|
+
@session = ret['session']
|
370
|
+
@base_url = ret['base_url']
|
371
|
+
@base_path = ret['base_path']
|
372
|
+
if @session.nil? or @base_url.nil? or @base_path.nil?
|
373
|
+
raise HandshakeError, "handshake error(session: #{@session}, base_url#{@base_url}, base_path: #{@base_path})"
|
374
|
+
else
|
375
|
+
puts "Success Handshake" if @verbose
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
ret
|
380
|
+
|
381
|
+
end
|
382
|
+
|
383
|
+
def _adjust_station(url)
|
384
|
+
|
385
|
+
ret = nil
|
386
|
+
|
387
|
+
h = {
|
388
|
+
'session' => @session,
|
389
|
+
'url' => @station,
|
390
|
+
'lang' => 'en'
|
391
|
+
}
|
392
|
+
query = _make_http_query(h)
|
393
|
+
path = "%s/%s?%s" % [@base_path,ADJUST_SCRIPT,query]
|
394
|
+
header = {
|
395
|
+
'Host' => @base_url,
|
396
|
+
'User-Agent' => @user_agent,
|
397
|
+
}
|
398
|
+
Net::HTTP.new(@base_url).request_get(path,header) do |res|
|
399
|
+
#ph res
|
400
|
+
ret = Hash[*res.body.split("\n").map{|i|i.split('=',2)}.flatten]
|
401
|
+
#ph ret
|
402
|
+
if ret['response'] == 'FAILED'
|
403
|
+
raise AdjustingError, AdjustingError::Messages[ret['error'].to_i-1]
|
404
|
+
else
|
405
|
+
puts "Success Adjusting #{ret[%[stationname]]} Station" if @verbose
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
ret['stationname']
|
410
|
+
|
411
|
+
end
|
412
|
+
|
413
|
+
def _get_tracks
|
414
|
+
|
415
|
+
ret = nil
|
416
|
+
|
417
|
+
h = {
|
418
|
+
'sk' => @session,
|
419
|
+
'desktop' => '1.4.2.58376',
|
420
|
+
}
|
421
|
+
query = _make_http_query(h)
|
422
|
+
path = "%s/%s?%s" % [@base_path,PLAYLIST_SCRIPT,query]
|
423
|
+
header = {
|
424
|
+
'Host' => @base_url,
|
425
|
+
'User-Agent' => @user_agent,
|
426
|
+
}
|
427
|
+
tracks = Array.new
|
428
|
+
|
429
|
+
xpath = '/playlist/trackList/track'
|
430
|
+
Net::HTTP.new(@base_url).request_get(path+query) do |res|
|
431
|
+
|
432
|
+
xspf = REXML::Document.new(res.body)
|
433
|
+
station = xspf.elements['/playlist/title']
|
434
|
+
if station.nil? or station.text.nil?
|
435
|
+
puts "Failure of Getting the Playlist Title" if @verbose
|
436
|
+
return []
|
437
|
+
end
|
438
|
+
|
439
|
+
station = station.text
|
440
|
+
station = CGI.unescape(station)
|
441
|
+
xspf.each_element(xpath) do |ele|
|
442
|
+
tr = Hash.new
|
443
|
+
ele.each_element do |child|
|
444
|
+
tr[child.name.to_sym] = child.text
|
445
|
+
end
|
446
|
+
tr[:station] = station
|
447
|
+
tr[:user_agent] = @user_agent
|
448
|
+
tracks << Track.new(tr)
|
449
|
+
end
|
450
|
+
end # End of "Net::HTTP.new(@base_url).request_get(..."
|
451
|
+
|
452
|
+
tracks
|
453
|
+
end
|
454
|
+
|
455
|
+
def _make_http_query(hash)
|
456
|
+
hash.to_a.map{|a|a.join('=')}.join('&')
|
457
|
+
end
|
458
|
+
|
459
|
+
def ph(h)
|
460
|
+
puts "-"*20 + h.class.to_s + "-"*20
|
461
|
+
h.each{|k,v|puts " #{k}\t=> #{v}"}
|
462
|
+
end
|
463
|
+
|
464
|
+
# make a last.fm url
|
465
|
+
def _make_lastfm_url(param_name,param)
|
466
|
+
tmp = "lastfm://%s/%s"
|
467
|
+
param_name = param_name.to_sym
|
468
|
+
param = URI.encode(param.to_s)
|
469
|
+
case param_name
|
470
|
+
when :personal
|
471
|
+
tmp % ["user", "#{param}/personal"]
|
472
|
+
when :tag, :tags, :globaltags
|
473
|
+
tmp % ["globaltags", param]
|
474
|
+
when :creator, :artist
|
475
|
+
tmp % ["artist", param]
|
476
|
+
when :group
|
477
|
+
tmp % ["group", param]
|
478
|
+
when :neighbours
|
479
|
+
tmp % ["user", "#{param}/neighbours"]
|
480
|
+
when :recommended
|
481
|
+
tmp % ["user", "#{param}/recommended/100"]
|
482
|
+
end
|
483
|
+
end
|
484
|
+
|
485
|
+
end
|
486
|
+
|
487
|
+
if $0 == __FILE__
|
488
|
+
Lastfm12.new("daftbeats","iamcrz4b",:station => ["tag","bossa"]).get_tracks.each do |tr|
|
489
|
+
puts tr
|
490
|
+
end
|
491
|
+
end
|
data/script/console
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# File: script/console
|
3
|
+
irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
|
4
|
+
|
5
|
+
libs = " -r irb/completion"
|
6
|
+
# Perhaps use a console_lib to store any extra methods I may want available in the cosole
|
7
|
+
# libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
|
8
|
+
libs << " -r #{File.dirname(__FILE__) + '/../lib/lastfm12.rb'}"
|
9
|
+
puts "Loading lastfm12 gem"
|
10
|
+
exec "#{irb} #{libs} --simple-prompt"
|