hearken 0.1.2 → 0.1.3
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 +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
|