robut-rdio 0.1.0 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/lib/server/server.rb CHANGED
@@ -34,6 +34,14 @@ class Robut::Plugin::Rdio
34
34
 
35
35
  # The domain associated with +token+. Defaults to localhost.
36
36
  attr_accessor :domain
37
+
38
+ # A callback set by to Robut plugin so the server can talk to it
39
+ attr_accessor :reply_callback
40
+
41
+ # A callback for Hipchat Chat room to set the state of the robut
42
+ attr_accessor :state_callback
43
+
44
+ attr_accessor :last_played_track
37
45
  end
38
46
  self.queue = []
39
47
  self.command = []
@@ -64,7 +72,34 @@ END
64
72
  self.class.command = []
65
73
  command.to_json
66
74
  end
75
+
76
+ # Make an announcement into the Hipchat channel
77
+ get '/announcement/:message' do
78
+ self.announce! URI.unescape(params[:message].to_s)
79
+ end
67
80
 
81
+ # Make a now playing announcmenet into the Hipchat channel
82
+ get '/now_playing/:title' do
83
+ track_title = URI.unescape(params[:title].to_s)
84
+
85
+ if self.track_is_not_the_same_as_last? track_title
86
+ self.state! "is now playing: #{track_title}"
87
+ self.class.last_played_track = track_title
88
+ end
89
+ end
90
+
91
+ def state!(message)
92
+ self.class.state_callback.call(message) if self.class.state_callback
93
+ end
94
+
95
+ def announce!(message)
96
+ self.class.reply_callback.call(message) if self.class.reply_callback
97
+ end
98
+
99
+ def track_is_not_the_same_as_last? current_track
100
+ self.class.last_played_track != current_track
101
+ end
102
+
68
103
  # start the server if ruby file executed directly
69
104
  run! if app_file == $0
70
105
  end
data/plugin-tester.rb CHANGED
@@ -16,7 +16,7 @@ def @plugin.nick
16
16
  return 'dj'
17
17
  end
18
18
 
19
- def @plugin.reply(msg)
19
+ def @plugin.reply(msg, to = nil)
20
20
  puts msg
21
21
  end
22
22
 
data/robut-rdio.gemspec CHANGED
@@ -5,27 +5,27 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "robut-rdio"
8
- s.version = "0.1.0"
8
+ s.version = "0.1.2"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Adam Pearson"]
12
- s.date = "2011-11-10"
12
+ s.date = "2011-12-08"
13
13
  s.description = ""
14
14
  s.email = "ampearson@gmail.com"
15
15
  s.extra_rdoc_files = [
16
16
  "LICENSE.txt",
17
- "README.md",
18
- "README.rdoc"
17
+ "README.md"
19
18
  ]
20
19
  s.files = [
21
20
  ".document",
22
21
  ".rspec",
23
22
  ".rvmrc",
23
+ "CHANGELOG.md",
24
24
  "Gemfile",
25
25
  "Gemfile.lock",
26
+ "Guardfile",
26
27
  "LICENSE.txt",
27
28
  "README.md",
28
- "README.rdoc",
29
29
  "Rakefile",
30
30
  "VERSION",
31
31
  "lib/robut-rdio.rb",
@@ -33,6 +33,12 @@ Gem::Specification.new do |s|
33
33
  "lib/server/public/css/style.css",
34
34
  "lib/server/public/css/style_after.css",
35
35
  "lib/server/public/images/background.png",
36
+ "lib/server/public/images/buffering.png",
37
+ "lib/server/public/images/circle-east.png",
38
+ "lib/server/public/images/circle-pause.png",
39
+ "lib/server/public/images/circle-play.png",
40
+ "lib/server/public/images/circle-stop.png",
41
+ "lib/server/public/images/disconnected.png",
36
42
  "lib/server/public/images/no-album.png",
37
43
  "lib/server/public/index.html",
38
44
  "lib/server/public/js/libs/dd_belatedpng.js",
@@ -44,8 +50,11 @@ Gem::Specification.new do |s|
44
50
  "lib/tasks/shell.rake",
45
51
  "plugin-tester.rb",
46
52
  "robut-rdio.gemspec",
53
+ "spec/integration/robut-rdio_spec.rb",
47
54
  "spec/robut-rdio_spec.rb",
48
- "spec/spec_helper.rb"
55
+ "spec/server_spec.rb",
56
+ "spec/spec_helper.rb",
57
+ "spec/support/shared_examples.rb"
49
58
  ]
50
59
  s.homepage = "http://github.com/radamant/robut-rdio"
51
60
  s.licenses = ["MIT"]
@@ -58,35 +67,44 @@ Gem::Specification.new do |s|
58
67
 
59
68
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
60
69
  s.add_runtime_dependency(%q<robut>, [">= 0"])
61
- s.add_development_dependency(%q<thin>, [">= 0"])
62
- s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
70
+ s.add_runtime_dependency(%q<rdio>, ["= 0.0.91"])
71
+ s.add_runtime_dependency(%q<sinatra>, [">= 0"])
72
+ s.add_runtime_dependency(%q<thin>, [">= 0"])
73
+ s.add_development_dependency(%q<rspec>, [">= 0"])
63
74
  s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
64
75
  s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
65
76
  s.add_development_dependency(%q<rcov>, [">= 0"])
66
- s.add_development_dependency(%q<rdio>, ["= 0.0.91"])
67
- s.add_development_dependency(%q<sinatra>, [">= 0"])
68
77
  s.add_development_dependency(%q<highline>, [">= 0"])
78
+ s.add_development_dependency(%q<guard>, [">= 0"])
79
+ s.add_development_dependency(%q<guard-rspec>, [">= 0"])
80
+ s.add_development_dependency(%q<ruby-debug19>, [">= 0"])
69
81
  else
70
82
  s.add_dependency(%q<robut>, [">= 0"])
83
+ s.add_dependency(%q<rdio>, ["= 0.0.91"])
84
+ s.add_dependency(%q<sinatra>, [">= 0"])
71
85
  s.add_dependency(%q<thin>, [">= 0"])
72
- s.add_dependency(%q<rspec>, ["~> 2.3.0"])
86
+ s.add_dependency(%q<rspec>, [">= 0"])
73
87
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
74
88
  s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
75
89
  s.add_dependency(%q<rcov>, [">= 0"])
76
- s.add_dependency(%q<rdio>, ["= 0.0.91"])
77
- s.add_dependency(%q<sinatra>, [">= 0"])
78
90
  s.add_dependency(%q<highline>, [">= 0"])
91
+ s.add_dependency(%q<guard>, [">= 0"])
92
+ s.add_dependency(%q<guard-rspec>, [">= 0"])
93
+ s.add_dependency(%q<ruby-debug19>, [">= 0"])
79
94
  end
80
95
  else
81
96
  s.add_dependency(%q<robut>, [">= 0"])
97
+ s.add_dependency(%q<rdio>, ["= 0.0.91"])
98
+ s.add_dependency(%q<sinatra>, [">= 0"])
82
99
  s.add_dependency(%q<thin>, [">= 0"])
83
- s.add_dependency(%q<rspec>, ["~> 2.3.0"])
100
+ s.add_dependency(%q<rspec>, [">= 0"])
84
101
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
85
102
  s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
86
103
  s.add_dependency(%q<rcov>, [">= 0"])
87
- s.add_dependency(%q<rdio>, ["= 0.0.91"])
88
- s.add_dependency(%q<sinatra>, [">= 0"])
89
104
  s.add_dependency(%q<highline>, [">= 0"])
105
+ s.add_dependency(%q<guard>, [">= 0"])
106
+ s.add_dependency(%q<guard-rspec>, [">= 0"])
107
+ s.add_dependency(%q<ruby-debug19>, [">= 0"])
90
108
  end
91
109
  end
92
110
 
@@ -0,0 +1,119 @@
1
+ require_relative '../spec_helper'
2
+
3
+ # Wherein we test legacy code, and hopefully refactor and remove this file
4
+ describe "RobutRdio Super Integration Test" do
5
+
6
+ let(:plugin) do
7
+ plugin = Robut::Plugin::Rdio.new(nil)
8
+
9
+ def plugin.nick
10
+ "dj"
11
+ end
12
+
13
+ plugin.stub(:reply){ |msg| @reply = msg }
14
+
15
+ plugin
16
+ end
17
+
18
+ def say(msg)
19
+ plugin.handle(Time.now, 'foo bar', msg)
20
+ end
21
+
22
+ it 'should set up a callback for the Server on startup' do
23
+ say('boo')
24
+ Robut::Plugin::Rdio::Server.reply_callback.should_not be_nil
25
+ end
26
+
27
+ describe "searching for tracks" do
28
+
29
+ it 'should make an rdio search' do
30
+ stub_search('neil young', ['harvest', 'after the gold rush'])
31
+ say('@dj find neil young')
32
+ @reply.should == "result: harvest\nresult: after the gold rush\n"
33
+ end
34
+
35
+ def stub_search(mock_query, results)
36
+ plugin.stub(:search).with(mock_query) { results }
37
+ results.each do |result|
38
+ plugin.stub(:format_result).with(result, anything()) { "result: #{result}" }
39
+ end
40
+ end
41
+
42
+
43
+ end
44
+
45
+ describe 'queuing tracks' do
46
+
47
+ describe 'when there is a search result' do
48
+ before do
49
+ plugin.stub(:result_at) { |i| i.to_s }
50
+ plugin.stub(:queue) { |result| @queued = result }
51
+ plugin.stub(:has_results?) { true }
52
+ plugin.stub(:has_result?) { true }
53
+ end
54
+
55
+ it 'should queue the track at the given position with "play <number>"' do
56
+ say '@dj play 1'
57
+ @queued.should == '1'
58
+
59
+ say '@dj 8'
60
+ @queued.should == '8'
61
+ end
62
+
63
+ end
64
+
65
+ describe 'when there are no search results' do
66
+ before do
67
+ plugin.stub(:has_results?) { false }
68
+ end
69
+
70
+ it 'should say there are no results' do
71
+ say '@dj play 9'
72
+ @reply.should == "I don't have any search results"
73
+ end
74
+ end
75
+
76
+ describe 'when there are results but not at the requested index' do
77
+ before do
78
+ plugin.stub(:has_results?) { true }
79
+ plugin.stub(:has_result?).with(5) { false }
80
+ end
81
+ it 'should say the result does not exist' do
82
+ say '@dj play 5'
83
+ @reply.should == "I don't have that result"
84
+ end
85
+ end
86
+ end
87
+
88
+ describe "I'm feeling lucky play/search" do
89
+
90
+ end
91
+ describe 'running commands' do
92
+ before do
93
+ plugin.stub(:run_command) { |command| @command = command }
94
+ end
95
+
96
+ %w{play unpause pause next restart back clear}.each do |command|
97
+ it "should run #{command}" do
98
+ say("@dj #{command}")
99
+ @command.should == command
100
+ end
101
+ end
102
+ end
103
+
104
+ describe 'skipping an album' do
105
+ before do
106
+ plugin.stub(:run_command) { |command| @command = command }
107
+ end
108
+ it "should run next_album for `next album`" do
109
+ say("@dj next album")
110
+ @command.should == "next_album"
111
+ end
112
+
113
+ it "should run next_album for `skip album`" do
114
+ say("@dj skip album")
115
+ @command.should == "next_album"
116
+ end
117
+ end
118
+
119
+ end
@@ -1,101 +1,244 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
1
+ require 'spec_helper'
2
2
 
3
- # Wherein we test legacy code, and hopefully refactor and remove this file
4
- describe "RobutRdio Super Integration Test" do
5
- let(:plugin) do plugin = Robut::Plugin::Rdio.new(nil)
6
- def plugin.nick
7
- "dj"
8
- end
9
-
10
-
11
- plugin.stub(:reply){|msg|
12
- @reply = msg
3
+ describe Robut::Plugin::Rdio do
4
+
5
+ subject {
6
+ connection = double("connection")
7
+ connection.stub_chain(:config, :nick) { "dj" }
8
+ connection.stub(:store).and_return(store)
9
+ connection.stub(:reply).and_return(nil)
10
+ Robut::Plugin::Rdio.new connection
13
11
  }
14
-
15
- plugin
16
- end
17
-
18
- def say(msg)
19
- plugin.handle(Time.now, 'foo bar', msg)
20
- end
21
-
22
- describe "searching for tracks" do
23
-
24
-
25
- it 'should make an rdio search' do
26
- stub_search('neil young', ['harvest', 'after the gold rush'])
27
- say('@dj find neil young')
28
- @reply.should == "result: harvest\nresult: after the gold rush\n"
29
- end
30
-
31
- def stub_search(mock_query, results)
32
- plugin.stub(:search).with(['', mock_query]){results}
33
- results.each do |result|
34
- plugin.stub(:format_result).with(result, anything()){"result: #{result}"}
35
- end
12
+
13
+ let(:sender) { "sender" }
14
+
15
+ let!(:store) { {} }
16
+
17
+ let(:time) { Time.now }
18
+
19
+ describe "#usage" do
20
+
21
+ # Though it is acceptable for the plugin to return a String here,
22
+ # it is important that we return an Enumerable list of instruction examples
23
+ # as we have so many different commands.
24
+ it "should return a list of commands on how to use the plugin" do
25
+ subject.usage.should be_kind_of(Enumerable)
36
26
  end
37
-
38
27
 
39
28
  end
40
-
41
- describe 'queuing tracks' do
42
-
43
- describe 'when there is a search result' do
44
- before do
45
- plugin.stub(:result_at){|i| i.to_s}
46
- plugin.stub(:queue){|result| @queued = result}
47
- plugin.stub(:has_results?){true}
48
- plugin.stub(:has_result?){true}
29
+
30
+ describe "Routing Methods" do
31
+
32
+ describe "#play?", :method => :play? do
33
+
34
+ it_should_behave_like "a routing method"
35
+
36
+ let(:valid_requests) do
37
+ [
38
+ # play keyword
39
+ "play 0",
40
+ "play 999999",
41
+ [ "play", "0" ],
42
+ # result keyword
43
+ "result1",
44
+ "result 1",
45
+ [ "result 0"],
46
+ # multiple tracks
47
+ "play 1, 2, 3",
48
+ "play 1 2 3",
49
+ "play 1 - 3",
50
+ "play 1-3",
51
+ # all tracks
52
+ "play all"
53
+ ]
49
54
  end
50
55
 
51
- it 'should queue the track at the given position with "play <number>"' do
52
- say '@dj play 1'
53
- @queued.should == '1'
54
-
55
- say '@dj 8'
56
- @queued.should == '8'
56
+ let(:invalid_requests) do
57
+ [
58
+ "play Abba",
59
+ "play ",
60
+ [ "play", "three-eleven" ]
61
+ ]
57
62
  end
58
63
 
59
64
  end
60
-
61
- describe 'when there are no search results' do
62
- before do
63
- plugin.stub(:has_results?){false}
65
+
66
+ describe "search?", :method => :search? do
67
+
68
+ it_should_behave_like "a routing method"
69
+
70
+ let(:valid_requests) do
71
+ [
72
+ "find the beatles",
73
+ "do you have any grey poupon",
74
+ [ "find", "breeders" ],
75
+ "do you have Weezer",
76
+ "find finding nemo"
77
+ ]
64
78
  end
65
79
 
66
- it 'should say there are no results' do
67
- say '@dj play 9'
68
- @reply.should == "I don't have any search results"
80
+ let(:invalid_requests) do
81
+ [
82
+ "play Abba",
83
+ "play ",
84
+ [ "play", "three-eleven" ]
85
+ ]
69
86
  end
87
+
70
88
  end
71
-
72
- describe 'when there are results but not at the requested index' do
73
- before do
74
- plugin.stub(:has_results?){true}
75
- plugin.stub(:has_result?).with(5){false}
89
+
90
+ describe "#search_and_play?", :method => :search_and_play? do
91
+
92
+ it_should_behave_like "a routing method"
93
+
94
+ let(:valid_requests) do
95
+ [
96
+ "play the beatles",
97
+ [ "play", "breeders" ],
98
+ "play doh re me ...",
99
+ "play me a song mister piano man"
100
+ ]
76
101
  end
77
- it 'should say the result does not exist' do
78
- say '@dj play 5'
79
- @reply.should == "I don't have that result"
102
+
103
+ let(:invalid_requests) do
104
+ [
105
+ "play",
106
+ "find this and play it for me",
107
+ " play even with that space at the start",
108
+ [ "plato", "first", "album" ]
109
+ ]
80
110
  end
111
+
81
112
  end
113
+
114
+ describe "#command?", :method => :command? do
115
+
116
+ it_should_behave_like "a routing method"
117
+
118
+ let(:valid_requests) do
119
+ [
120
+ "play",
121
+ "pause",
122
+ "unpause",
123
+ "next",
124
+ "restart",
125
+ "back",
126
+ "clear",
127
+ [ "play" ]
128
+ ]
129
+ end
130
+
131
+ let(:invalid_requests) do
132
+ [
133
+ " play",
134
+ "play ",
135
+ "player",
136
+ "play-pause",
137
+ "clearing house"
138
+ ]
139
+ end
140
+
141
+ end
142
+
82
143
  end
83
-
84
- describe "I'm feeling lucky play/search" do
85
144
 
86
- end
87
-
88
- describe 'running commands' do
89
- before do
90
- plugin.stub(:run_command){|command| @command = command}
145
+ describe "#handle" do
146
+
147
+ it "should create a communication channel with the music server" do
148
+
149
+ subject.should_receive(:establish_server_callbacks!).and_return(nil)
150
+ subject.handle(time,"","")
151
+
91
152
  end
92
153
 
93
- %w{play unpause pause next restart back clear}.each do |command|
94
- it "should run #{command}" do
95
- say("@dj #{command}")
96
- @command.should == command
154
+ context "when not sent to the agent" do
155
+
156
+ let(:message) { "This message does not mention the dj" }
157
+
158
+ it "should perform no action" do
159
+
160
+ subject.should_not_receive(:play?)
161
+ subject.handle(time,sender,message)
162
+
97
163
  end
164
+
98
165
  end
166
+
167
+ context "when sent to the agent" do
168
+
169
+ context "when it is a play request" do
170
+
171
+ let(:message) { "@dj play 0" }
172
+
173
+ it_should_behave_like "a successfully routed action",
174
+ :route => :play?, :action => :play_result, :parameters => 0
175
+
176
+ end
177
+
178
+ context "when it is a multiple play request" do
179
+
180
+ let(:message) { "@dj play 1, 4 5-7" }
181
+
182
+ it_should_behave_like "a successfully routed action",
183
+ :route => :play?, :action => :play_result, :parameters => [1,4,5,6,7]
184
+
185
+ end
186
+
187
+ context "when it is a search and play request" do
188
+
189
+ let(:message) { "@dj play the misfits" }
190
+
191
+ context "when the search returns a result" do
192
+
193
+ it_should_behave_like "a successfully routed action",
194
+ :route => :search_and_play?, :action => :search_and_play_result,
195
+ :parameters => "the misfits", :returning => true
196
+
197
+ end
198
+
199
+ context "when the search result does not return a result" do
200
+
201
+ before :each do
202
+ subject.should_receive(:reply).with("I couldn't find 'the misfits' on Rdio.")
203
+ end
204
+
205
+ it_should_behave_like "a successfully routed action",
206
+ :route => :search_and_play?, :action => :search_and_play_result, :parameters => "the misfits"
207
+
208
+ end
209
+
210
+ end
211
+
212
+ context "when it is a search request" do
213
+
214
+ let(:message) { "@dj find the partridge family" }
215
+
216
+ it_should_behave_like "a successfully routed action",
217
+ :route => :search?, :action => :find, :parameters => "the partridge family"
218
+
219
+ end
220
+
221
+ context "when it is a skip album request" do
222
+
223
+ let(:message) { "skip album @dj" }
224
+
225
+ it_should_behave_like "a successfully routed action",
226
+ :route => :skip_album?, :action => :run_command, :parameters => "next_album"
227
+
228
+ end
229
+
230
+ context "when it is command" do
231
+
232
+ let(:message) { "@dj pause" }
233
+
234
+ it_should_behave_like "a successfully routed action",
235
+ :route => :command?, :action => :run_command, :parameters => "pause"
236
+
237
+ end
238
+
239
+ end
240
+
241
+
99
242
  end
100
-
243
+
101
244
  end