hearken 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.rubocop.yml +14 -0
- data/.tool-versions +1 -0
- data/Gemfile +7 -1
- data/Gemfile.lock +95 -0
- data/{README.rdoc → README.md} +12 -50
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/exe/hearken +9 -0
- data/exe/hearken_index +13 -0
- data/hearken.gemspec +35 -35
- data/lib/hearken/command/enqueue.rb +35 -10
- data/lib/hearken/command/reload.rb +18 -6
- data/lib/hearken/command/search.rb +31 -20
- data/lib/hearken/console.rb +11 -28
- data/lib/hearken/debug.rb +6 -6
- data/lib/hearken/indexing/indexer.rb +32 -24
- data/lib/hearken/library.rb +49 -41
- data/lib/hearken/monkey_violence.rb +9 -7
- data/lib/hearken/paths.rb +13 -19
- data/lib/hearken/range_expander.rb +18 -13
- data/lib/hearken/tagged.rb +15 -11
- data/lib/hearken/track.rb +53 -41
- data/lib/hearken.rb +2 -2
- metadata +26 -105
- data/.gitignore +0 -5
- data/HISTORY.rdoc +0 -38
- data/MIT-LICENSE +0 -20
- data/bin/hearken +0 -7
- data/bin/hearken_index +0 -12
- data/bin/hearken_scrobble +0 -35
- data/bin/hearken_tags +0 -11
- data/lib/hearken/command/list.rb +0 -32
- data/lib/hearken/command/love.rb +0 -7
- data/lib/hearken/command/profile.rb +0 -7
- data/lib/hearken/command/recent.rb +0 -38
- data/lib/hearken/command/remove.rb +0 -15
- data/lib/hearken/command/restart.rb +0 -7
- data/lib/hearken/command/scrobbling.rb +0 -14
- data/lib/hearken/command/setup_scrobbling.rb +0 -7
- data/lib/hearken/command/shuffle.rb +0 -13
- data/lib/hearken/command/start.rb +0 -7
- data/lib/hearken/command/status.rb +0 -7
- data/lib/hearken/command/stop.rb +0 -7
- data/lib/hearken/command.rb +0 -35
- data/lib/hearken/notification/growl_notifier.rb +0 -15
- data/lib/hearken/player.rb +0 -130
- data/lib/hearken/preferences.rb +0 -33
- data/lib/hearken/queue.rb +0 -33
- data/lib/hearken/scrobbler.rb +0 -82
- data/lib/hearken/simple_scrobbler.rb +0 -94
- data/media/ice_cream.png +0 -0
- data/spec/hearken/command/enqueue_spec.rb +0 -24
- data/spec/hearken/command/list_spec.rb +0 -31
- data/spec/hearken/command/reload_spec.rb +0 -21
- data/spec/hearken/command/shuffle_spec.rb +0 -33
- data/spec/hearken/player_spec.rb +0 -38
- data/spec/hearken/range_expander_spec.rb +0 -28
- data/spec/spec_helper.rb +0 -16
data/bin/hearken_scrobble
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
$: << File.dirname(__FILE__)+'/../lib'
|
4
|
-
|
5
|
-
command = ARGV.shift
|
6
|
-
|
7
|
-
unless %w{setup start finish}.include? command
|
8
|
-
puts 'usage:'
|
9
|
-
puts ' hearken_scrobble setup'
|
10
|
-
puts ' hearken_scrobble start PATH_TO_AUDIO_FILE'
|
11
|
-
puts ' hearken_scrobble finish PATH_TO_AUDIO_FILE'
|
12
|
-
exit 0
|
13
|
-
end
|
14
|
-
|
15
|
-
require 'hearken/indexing/ffmpeg_file'
|
16
|
-
require 'hearken/scrobbler'
|
17
|
-
|
18
|
-
scrobbler = Hearken::Scrobbler.new
|
19
|
-
scrobbler.enabled = true
|
20
|
-
|
21
|
-
if command == 'setup'
|
22
|
-
scrobbler.setup
|
23
|
-
exit 0
|
24
|
-
end
|
25
|
-
|
26
|
-
file = ARGV.shift
|
27
|
-
track = Hearken::Indexing::FfmpegFile.from_file file
|
28
|
-
|
29
|
-
if command == 'start'
|
30
|
-
scrobbler.started track
|
31
|
-
elsif command == 'finish'
|
32
|
-
scrobbler.finished track
|
33
|
-
else
|
34
|
-
puts 'unknown command'
|
35
|
-
end
|
data/bin/hearken_tags
DELETED
data/lib/hearken/command/list.rb
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
require 'hearken/command'
|
2
|
-
require 'hearken/colour'
|
3
|
-
|
4
|
-
class Hearken::Command::List
|
5
|
-
include Hearken::Command
|
6
|
-
include Hearken::Colour
|
7
|
-
|
8
|
-
usage '*<word>'
|
9
|
-
help <<EOF
|
10
|
-
lists the contents of the track queue
|
11
|
-
these results can optionally be filtered by specified words
|
12
|
-
when playing, approximate times for each track will be displayed
|
13
|
-
EOF
|
14
|
-
execute do |text|
|
15
|
-
@terms = text.split(/\W/)
|
16
|
-
current = @player.current
|
17
|
-
if current
|
18
|
-
next_start_time = Time.at current.started
|
19
|
-
show next_start_time, current
|
20
|
-
end
|
21
|
-
next_start_time += current.time.to_i if next_start_time && current.time
|
22
|
-
@player.each do |track|
|
23
|
-
show next_start_time, track
|
24
|
-
next_start_time += track.time.to_i if next_start_time && track.time
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def show time, track
|
29
|
-
return unless @terms.empty? or @terms.all? {|term| track.search_string.include? term }
|
30
|
-
puts time ? "#{c time.strftime("%H:%M:%S %d/%m/%Y"), :blue} #{track}" : track
|
31
|
-
end
|
32
|
-
end
|
data/lib/hearken/command/love.rb
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
require 'hearken/command'
|
2
|
-
require 'hearken/colour'
|
3
|
-
|
4
|
-
class Hearken::Command::Recent
|
5
|
-
include Hearken::Command
|
6
|
-
include Hearken::Colour
|
7
|
-
|
8
|
-
usage '<count>'
|
9
|
-
help 'lists the specified number of recently added albums'
|
10
|
-
execute do |text|
|
11
|
-
@player.library.reload unless @player.library.tracks
|
12
|
-
all_tracks = @player.library.tracks.sort do |a, b|
|
13
|
-
tc = a.timestamp <=> b.timestamp
|
14
|
-
tc == 0 ? a.id <=> b.id : tc
|
15
|
-
end
|
16
|
-
maximum, current_album, tracks, total_count = text.to_i, nil, [], 0
|
17
|
-
all_tracks.reverse.each do |track|
|
18
|
-
unless current_album
|
19
|
-
current_album = track.album
|
20
|
-
tracks = [track]
|
21
|
-
next
|
22
|
-
end
|
23
|
-
if current_album==track.album
|
24
|
-
tracks << track
|
25
|
-
else
|
26
|
-
puts "#{c extract_artist(tracks), :yellow} #{c current_album, :cyan} #{tracks.size} tracks [#{tracks.last.search_id}-#{tracks.first.search_id}]"
|
27
|
-
current_album = track.album
|
28
|
-
tracks = [track]
|
29
|
-
total_count += 1
|
30
|
-
end
|
31
|
-
break if total_count >= maximum
|
32
|
-
end
|
33
|
-
end
|
34
|
-
private
|
35
|
-
def extract_artist tracks
|
36
|
-
tracks.map{|t| t.artist}.uniq.size == 1 ? tracks.first.artist : 'various artists'
|
37
|
-
end
|
38
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
require 'hearken/command'
|
2
|
-
|
3
|
-
class Hearken::Command::Remove
|
4
|
-
include Hearken::Command
|
5
|
-
usage '*<word>'
|
6
|
-
help 'removes all tracks that match the specified criteria - specifying no criteria will flush entire queue'
|
7
|
-
execute do |text|
|
8
|
-
@terms = text.split(/\W/)
|
9
|
-
ids = []
|
10
|
-
while track = @player.dequeue
|
11
|
-
ids << track.id unless @terms.all? {|term| track.search_string.include? term }
|
12
|
-
end
|
13
|
-
ids.each {|id| @player.enqueue id }
|
14
|
-
end
|
15
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
require 'hearken/command'
|
2
|
-
|
3
|
-
class Hearken::Command::Scrobbling
|
4
|
-
include Hearken::Command
|
5
|
-
usage '<on|off>'
|
6
|
-
help 'turns interaction with lastfm on or off'
|
7
|
-
execute do |text|
|
8
|
-
scrobbling = (text == 'on')
|
9
|
-
return if @player.scrobbling == scrobbling
|
10
|
-
puts scrobbling ? 'Turning scrobbling on' : 'Turning scrobbling off'
|
11
|
-
@player.scrobbling = scrobbling
|
12
|
-
@player.restart
|
13
|
-
end
|
14
|
-
end
|
@@ -1,13 +0,0 @@
|
|
1
|
-
require 'hearken/command'
|
2
|
-
|
3
|
-
class Hearken::Command::Shuffle
|
4
|
-
include Hearken::Command
|
5
|
-
help 'shuffles the current queue'
|
6
|
-
execute do |ignored=nil|
|
7
|
-
ids = []
|
8
|
-
while track = @player.dequeue
|
9
|
-
ids << track.id
|
10
|
-
end
|
11
|
-
ids.sort_by { rand }.each {|id| @player.enqueue id }
|
12
|
-
end
|
13
|
-
end
|
data/lib/hearken/command/stop.rb
DELETED
data/lib/hearken/command.rb
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
module Hearken
|
2
|
-
module Command
|
3
|
-
attr_reader :usage, :help
|
4
|
-
|
5
|
-
def self.included cls
|
6
|
-
cls.extend ClassMethods
|
7
|
-
end
|
8
|
-
|
9
|
-
def self.load name, *args
|
10
|
-
require "hearken/command/#{name}"
|
11
|
-
classname = name.to_s.split('_').map{|s|s.capitalize}.join
|
12
|
-
Hearken::Command.const_get(classname).new *args
|
13
|
-
end
|
14
|
-
|
15
|
-
def initialize player
|
16
|
-
@player = player
|
17
|
-
@usage = ''
|
18
|
-
@help = ''
|
19
|
-
end
|
20
|
-
|
21
|
-
module ClassMethods
|
22
|
-
def usage usage
|
23
|
-
define_method(:usage) { usage }
|
24
|
-
end
|
25
|
-
|
26
|
-
def help help
|
27
|
-
define_method(:help) { help }
|
28
|
-
end
|
29
|
-
|
30
|
-
def execute &block
|
31
|
-
define_method :execute, block
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
require 'hearken/monkey_violence'
|
2
|
-
|
3
|
-
module Hearken::Notification
|
4
|
-
end
|
5
|
-
|
6
|
-
class Hearken::Notification::GrowlNotifier
|
7
|
-
def initialize preferences
|
8
|
-
@growlnotify = !`which growlnotify`.chomp.empty?
|
9
|
-
@image_path = File.expand_path File.dirname(__FILE__)+'/../../../media/ice_cream.png'
|
10
|
-
end
|
11
|
-
|
12
|
-
def started track
|
13
|
-
`growlnotify -t "Hearken unto ..." --image #{@image_path} -m \"#{track.to_short_s.escape_for_sh_quoted}\"` if @growlnotify
|
14
|
-
end
|
15
|
-
end
|
data/lib/hearken/player.rb
DELETED
@@ -1,130 +0,0 @@
|
|
1
|
-
require 'fileutils'
|
2
|
-
|
3
|
-
require 'hearken/queue'
|
4
|
-
require 'hearken/scrobbler'
|
5
|
-
require 'hearken/notification/growl_notifier'
|
6
|
-
require 'hearken/library'
|
7
|
-
require 'hearken/colour'
|
8
|
-
|
9
|
-
module Hearken
|
10
|
-
class Player
|
11
|
-
include Queue
|
12
|
-
include Colour
|
13
|
-
attr_reader :library, :scrobbler
|
14
|
-
|
15
|
-
def initialize preferences
|
16
|
-
@scrobbler = Scrobbler.new preferences
|
17
|
-
@scrobbler.enabled = true
|
18
|
-
@growl = Hearken::Notification::GrowlNotifier.new preferences
|
19
|
-
@notifiers = [@scrobbler, @growl]
|
20
|
-
@library = Library.new preferences
|
21
|
-
@library.reload
|
22
|
-
create_paths
|
23
|
-
end
|
24
|
-
|
25
|
-
def status
|
26
|
-
if @pid
|
27
|
-
track = self.current
|
28
|
-
played = Time.now.to_i-track.started
|
29
|
-
timing = "(#{c track.time.to_i-played, :yellow} remaining)" if track.time
|
30
|
-
puts "#{c Time.at(track.started).strftime("%H:%M:%S %d/%m/%Y"), :blue}: #{track} #{timing}"
|
31
|
-
else
|
32
|
-
puts c 'not playing', :yellow
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def love
|
37
|
-
@scrobbler.love current
|
38
|
-
end
|
39
|
-
|
40
|
-
def profile
|
41
|
-
@scrobbler.profile
|
42
|
-
end
|
43
|
-
|
44
|
-
def current
|
45
|
-
in_base_dir do
|
46
|
-
(@pid and File.exist?('current_song')) ? YAML.load_file('current_song') : nil
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def register track
|
51
|
-
track.started = Time.now.to_i
|
52
|
-
in_base_dir do
|
53
|
-
File.open('current_song', 'w') {|f| f.print track.to_yaml }
|
54
|
-
File.open('history', 'a') {|f| f.puts "#{track.started},#{track.path}"}
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def notify_started track
|
59
|
-
@notifiers.each {|notifier| notifier.started track if notifier.respond_to? :started}
|
60
|
-
end
|
61
|
-
|
62
|
-
def notify_finished track
|
63
|
-
@notifiers.each {|notifier| notifier.finished track if notifier.respond_to? :finished}
|
64
|
-
end
|
65
|
-
|
66
|
-
def scrobbling
|
67
|
-
@scrobbler.enabled
|
68
|
-
end
|
69
|
-
|
70
|
-
def scrobbling= tf
|
71
|
-
@scrobbler.enabled = tf
|
72
|
-
end
|
73
|
-
|
74
|
-
def random_track
|
75
|
-
@library.row (rand * @library.count).to_i
|
76
|
-
end
|
77
|
-
|
78
|
-
def start
|
79
|
-
return if @pid
|
80
|
-
if @library.count == 0
|
81
|
-
puts 'Player can not be started with an empty library'
|
82
|
-
puts 'Please run "hearken_index" in another shell and then \'reload\''
|
83
|
-
return
|
84
|
-
end
|
85
|
-
@pid = fork do
|
86
|
-
player_pid = nil
|
87
|
-
Signal.trap('TERM') do
|
88
|
-
Process.kill 'TERM', player_pid if player_pid
|
89
|
-
exit
|
90
|
-
end
|
91
|
-
loop do
|
92
|
-
track = dequeue || random_track
|
93
|
-
next unless track
|
94
|
-
unless File.exist? track.path
|
95
|
-
puts "skipping track as #{track.path} does not exist"
|
96
|
-
next
|
97
|
-
end
|
98
|
-
notify_started track
|
99
|
-
register track
|
100
|
-
player_pid = spawn play_command track.path
|
101
|
-
Process.wait player_pid
|
102
|
-
notify_finished track
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
def play_command path
|
108
|
-
if %w{m4a mp3}.include? path.split('.').last
|
109
|
-
"afplay \"#{path.escape("\`")}\""
|
110
|
-
else
|
111
|
-
"play -q \"#{path.escape("\`")}\""
|
112
|
-
end.tap do |command|
|
113
|
-
in_base_dir do
|
114
|
-
File.open('player', 'a') {|f| f.puts command }
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
def stop
|
120
|
-
return unless @pid
|
121
|
-
Process.kill 'TERM', @pid
|
122
|
-
@pid = nil
|
123
|
-
end
|
124
|
-
|
125
|
-
def restart
|
126
|
-
stop
|
127
|
-
start
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
data/lib/hearken/preferences.rb
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
require 'yaml'
|
2
|
-
require 'hearken/paths'
|
3
|
-
require 'hearken/monkey_violence'
|
4
|
-
|
5
|
-
module Hearken; end
|
6
|
-
|
7
|
-
module Hearken
|
8
|
-
class Preferences
|
9
|
-
include Hearken::Paths
|
10
|
-
|
11
|
-
def initialize
|
12
|
-
create_paths
|
13
|
-
if File.exists? preferences_path
|
14
|
-
@preferences = YAML.load_file preferences_path
|
15
|
-
else
|
16
|
-
@preferences = {}
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def [] key
|
21
|
-
@preferences[key]
|
22
|
-
end
|
23
|
-
|
24
|
-
def []= key, value
|
25
|
-
@preferences[key] = value
|
26
|
-
persist
|
27
|
-
end
|
28
|
-
|
29
|
-
def persist
|
30
|
-
File.open(preferences_path, 'w') {|f| f.puts @preferences.to_yaml}
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
data/lib/hearken/queue.rb
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
require 'hearken/paths'
|
2
|
-
|
3
|
-
module Hearken::Queue
|
4
|
-
include Hearken::Paths
|
5
|
-
|
6
|
-
def enqueue id
|
7
|
-
in_queue_dir do
|
8
|
-
@sequence ||= 0
|
9
|
-
@library.with_track id do |track|
|
10
|
-
File.open("#{Time.now.to_i}-#{@sequence.to_s.rjust(8,'0')}.song", 'w') {|f| f.print track.to_yaml }
|
11
|
-
@sequence += 1
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def each
|
17
|
-
in_queue_dir do
|
18
|
-
Dir.glob('*.song').sort.each do |file|
|
19
|
-
yield YAML.load_file file
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def dequeue
|
25
|
-
in_queue_dir do
|
26
|
-
file = Dir.glob('*.song').sort.first
|
27
|
-
return nil unless file
|
28
|
-
hash = YAML.load_file file
|
29
|
-
FileUtils.rm file
|
30
|
-
hash
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
data/lib/hearken/scrobbler.rb
DELETED
@@ -1,82 +0,0 @@
|
|
1
|
-
require 'hearken/preferences'
|
2
|
-
require 'hearken/simple_scrobbler'
|
3
|
-
require 'hearken/debug'
|
4
|
-
|
5
|
-
# Modified version of simple_scrobbler gem from https://github.com/threedaymonk/simple_scrobbler
|
6
|
-
module Hearken
|
7
|
-
class Scrobbler
|
8
|
-
API_KEY = '21f8c75ad38637220b20a03ad61219a4'
|
9
|
-
SECRET = 'ab77019c84eef8bc16bcfd5ba8db0c5d'
|
10
|
-
include Debug
|
11
|
-
|
12
|
-
def initialize preferences=Hearken::Preferences.new
|
13
|
-
@preferences = preferences
|
14
|
-
end
|
15
|
-
|
16
|
-
def enabled
|
17
|
-
!!@scrobbler
|
18
|
-
end
|
19
|
-
|
20
|
-
def enabled= tf
|
21
|
-
@scrobbler = nil
|
22
|
-
if @preferences['lastfm'] and tf
|
23
|
-
debug "Configuring scrobbler with #{@preferences['lastfm'].inspect}"
|
24
|
-
user, session = *%w{user session_key}.map{|k| @preferences['lastfm'][k]}
|
25
|
-
@scrobbler = SimpleScrobbler.new API_KEY, SECRET, user, session
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
def finished track
|
30
|
-
return unless @scrobbler
|
31
|
-
debug "Scrobbling to last fm: #{track}"
|
32
|
-
send_to_scrobbler :scrobble, track
|
33
|
-
end
|
34
|
-
|
35
|
-
def started track
|
36
|
-
return unless @scrobbler
|
37
|
-
debug "Updating now listening with last fm: #{track}"
|
38
|
-
send_to_scrobbler :now_playing, track
|
39
|
-
end
|
40
|
-
|
41
|
-
def love track
|
42
|
-
return unless @scrobbler and track
|
43
|
-
debug "Sending love to last fm: #{track}"
|
44
|
-
send_to_scrobbler :love, track
|
45
|
-
end
|
46
|
-
|
47
|
-
def profile
|
48
|
-
return unless @scrobbler
|
49
|
-
@scrobbler.with_profile_url {|url| system "open #{url}" }
|
50
|
-
end
|
51
|
-
|
52
|
-
def ask question
|
53
|
-
print question
|
54
|
-
$stdin.gets.chomp
|
55
|
-
end
|
56
|
-
|
57
|
-
def setup
|
58
|
-
preferences = {}
|
59
|
-
preferences['user'] = ask 'What is your lastfm user name ? '
|
60
|
-
@scrobbler = SimpleScrobbler.new API_KEY, SECRET, preferences['user']
|
61
|
-
preferences['session_key'] = @scrobbler.fetch_session_key do |url|
|
62
|
-
system "open '#{url}'"
|
63
|
-
ask 'Please hit enter when you\'ve allowed this application access to your account'
|
64
|
-
end
|
65
|
-
@preferences['lastfm'] = preferences
|
66
|
-
end
|
67
|
-
private
|
68
|
-
def send_to_scrobbler message, track
|
69
|
-
begin
|
70
|
-
debug %w{artist title time album track}.map {|k| "#{k}=#{track.send(k)}"}.join(',')
|
71
|
-
@scrobbler.send message, track.artist,
|
72
|
-
track.title,
|
73
|
-
:duration => track.time,
|
74
|
-
:album => track.album,
|
75
|
-
:trackNumber => track.track.to_i,
|
76
|
-
:timestamp => Time.now.to_i
|
77
|
-
rescue Exception => e
|
78
|
-
puts "Failed to scrobble: #{e}"
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
@@ -1,94 +0,0 @@
|
|
1
|
-
require "net/http"
|
2
|
-
require "digest/md5"
|
3
|
-
require "uri"
|
4
|
-
require "cgi"
|
5
|
-
require 'nokogiri'
|
6
|
-
require 'hearken/debug'
|
7
|
-
|
8
|
-
module Hearken; end
|
9
|
-
|
10
|
-
class Hearken::SimpleScrobbler
|
11
|
-
include Hearken::Debug
|
12
|
-
|
13
|
-
SCROBBLER_URL = 'http://ws.audioscrobbler.com/2.0/'
|
14
|
-
|
15
|
-
SubmissionError = Class.new(RuntimeError)
|
16
|
-
SessionError = Class.new(RuntimeError)
|
17
|
-
|
18
|
-
def initialize api_key, secret, user, session_key=nil
|
19
|
-
@api_key = api_key
|
20
|
-
@secret = secret
|
21
|
-
@user = user
|
22
|
-
@session_key = session_key
|
23
|
-
end
|
24
|
-
|
25
|
-
attr_reader :user, :api_key, :secret, :session_key
|
26
|
-
|
27
|
-
def session_key
|
28
|
-
@session_key or raise SessionError, "The session key must be set or fetched"
|
29
|
-
end
|
30
|
-
|
31
|
-
def fetch_session_key
|
32
|
-
doc = lfm :get, 'auth.gettoken'
|
33
|
-
request_token = doc.at('token').inner_text
|
34
|
-
yield "http://www.last.fm/api/auth/?api_key=#{api_key}&token=#{request_token}"
|
35
|
-
doc = lfm :get, 'auth.getsession', :token => request_token
|
36
|
-
@session_key = doc.at('key').inner_text
|
37
|
-
@user = doc.at('name').inner_text
|
38
|
-
@session_key
|
39
|
-
end
|
40
|
-
|
41
|
-
def with_profile_url
|
42
|
-
yield "http://www.last.fm/user/#{user}" if user
|
43
|
-
end
|
44
|
-
|
45
|
-
# http://www.last.fm/api/show?service=443
|
46
|
-
def scrobble artist, title, params={}
|
47
|
-
lfm_track 'track.scrobble', artist, title, params
|
48
|
-
end
|
49
|
-
|
50
|
-
# See http://www.last.fm/api/show?service=454 for more details
|
51
|
-
def now_playing artist, title, params={}
|
52
|
-
lfm_track 'track.updateNowPlaying', artist, title, params
|
53
|
-
end
|
54
|
-
|
55
|
-
# http://www.last.fm/api/show?service=260
|
56
|
-
def love artist, title, params={}
|
57
|
-
lfm_track 'track.love', artist, title, params
|
58
|
-
end
|
59
|
-
private
|
60
|
-
def lfm_track method, artist, title, params
|
61
|
-
doc = lfm :post, method, params.merge(:sk => session_key, :artist => artist, :track => title)
|
62
|
-
status = doc.at('lfm')['status']
|
63
|
-
raise SubmissionError, status unless status == 'ok'
|
64
|
-
end
|
65
|
-
|
66
|
-
def lfm get_or_post, method, parameters={}
|
67
|
-
p = signed_parameters parameters.merge :api_key => api_key, :method => method
|
68
|
-
debug p.inspect
|
69
|
-
xml = self.send get_or_post, SCROBBLER_URL, p
|
70
|
-
debug xml
|
71
|
-
Nokogiri::XML xml
|
72
|
-
end
|
73
|
-
|
74
|
-
def get url, parameters
|
75
|
-
query_string = sort_parameters(parameters).
|
76
|
-
map{ |k, v| "#{k}=#{CGI.escape(v)}" }.
|
77
|
-
join("&")
|
78
|
-
Net::HTTP.get_response(URI.parse(url + "?" + query_string)).body
|
79
|
-
end
|
80
|
-
|
81
|
-
def post url, parameters
|
82
|
-
Net::HTTP.post_form(URI.parse(url), parameters).body
|
83
|
-
end
|
84
|
-
|
85
|
-
def signed_parameters parameters
|
86
|
-
sorted = sort_parameters parameters
|
87
|
-
signature = Digest::MD5.hexdigest(sorted.flatten.join + secret)
|
88
|
-
parameters.merge :api_sig => signature
|
89
|
-
end
|
90
|
-
|
91
|
-
def sort_parameters parameters
|
92
|
-
parameters.map{ |k, v| [k.to_s, v.to_s] }.sort
|
93
|
-
end
|
94
|
-
end
|
data/media/ice_cream.png
DELETED
Binary file
|
@@ -1,24 +0,0 @@
|
|
1
|
-
require_relative '../../spec_helper'
|
2
|
-
require 'hearken/command/enqueue'
|
3
|
-
|
4
|
-
describe Hearken::Command::Enqueue do
|
5
|
-
extend ShellShock::CommandSpec
|
6
|
-
|
7
|
-
with_usage '*<id>'
|
8
|
-
with_help 'enqueues the list of songs with the specified ids'
|
9
|
-
|
10
|
-
before do
|
11
|
-
@player = double 'player'
|
12
|
-
@command = Hearken::Command::Enqueue.new @player
|
13
|
-
end
|
14
|
-
|
15
|
-
it 'should enqueue whatever is returned from the expander' do
|
16
|
-
expander = double 'expander'
|
17
|
-
allow(Hearken::RangeExpander).to receive(:new) { expander }
|
18
|
-
allow(expander).to receive(:expand).with('some text') { [1,2,3] }
|
19
|
-
|
20
|
-
[1,2,3].each {|id| expect(@player).to receive(:enqueue).with(id) }
|
21
|
-
|
22
|
-
@command.execute "some text"
|
23
|
-
end
|
24
|
-
end
|