robut-rdio 0.1.0 → 0.1.2

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/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