mpc 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.
Files changed (3) hide show
  1. data/lib/mpc.rb +264 -0
  2. data/test/mpc_test.rb +124 -0
  3. metadata +67 -0
data/lib/mpc.rb ADDED
@@ -0,0 +1,264 @@
1
+ class Mpc
2
+ @@regexps = {
3
+ "ACK" => /\AACK \[(\d+)\@(\d+)\] \{(.*)\} (.+)\Z/,
4
+ "OK" => /\AOK\n\Z/,
5
+ "FILE" => /\Afile\:(.*)\Z/,
6
+ }
7
+
8
+ def initialize(host = "127.0.0.1", port = 6600)
9
+ @socket = TCPSocket.new(host, port)
10
+ @socket.gets
11
+ end
12
+
13
+ def play(song = nil)
14
+ song.nil? ? command = "play" : command = "play #{song.to_s}"
15
+ puts(command)
16
+ end
17
+
18
+ def pause
19
+ puts("pause 1")
20
+ end
21
+
22
+ def paused?
23
+ status_hash = status
24
+ status_hash[:state] == "pause"
25
+ end
26
+
27
+ def stop
28
+ puts("stop")
29
+ end
30
+
31
+ def stopped?
32
+ status_hash = status
33
+ status_hash[:state] == "stop"
34
+ end
35
+
36
+ def next
37
+ puts("next")
38
+ end
39
+
40
+ def previous
41
+ puts("previous")
42
+ end
43
+
44
+ def random(state = nil)
45
+ if state.nil?
46
+ random? ? random_state = 0 : random_state = 1
47
+ else
48
+ random_state = state
49
+ end
50
+ puts("random #{random_state}")
51
+ end
52
+
53
+ def random?
54
+ status_hash = status
55
+ status_hash[:random] == "1"
56
+ end
57
+
58
+ def repeat(state = nil)
59
+ if state.nil?
60
+ repeat? ? repeat_state = 0 : repeat_state = 1
61
+ else
62
+ repeat_state = state
63
+ end
64
+ puts("repeat #{repeat_state}")
65
+ end
66
+
67
+ def repeat?
68
+ status_hash = status
69
+ status_hash[:repeat] == "1"
70
+ end
71
+
72
+ def set_volume(volume)
73
+ begin
74
+ unless (0..100).include?(volume)
75
+ raise Exception.new("Volume should be between 0 (minimum) and 100 (maximum)")
76
+ end
77
+ puts("setvol #{volume.to_s}")
78
+ end
79
+ end
80
+
81
+ def volume
82
+ status_hash = status
83
+ status_hash[:volume]
84
+ end
85
+
86
+ def volume_up
87
+ setvol(volume.to_i + 20)
88
+ end
89
+
90
+ def volume_down
91
+ setvol(volume.to_i - 20)
92
+ end
93
+
94
+ def seek(time, song = nil)
95
+ if song.nil?
96
+ song = current_song[:pos]
97
+ end
98
+ puts("seek #{song.to_s} #{time.to_s}")
99
+ end
100
+
101
+ def find(type, what = "")
102
+ unless type.match(/\A(title|artist|album|filename)\Z/)
103
+ raise Exception.new("Wrong type: #{type}")
104
+ end
105
+ if what == ""
106
+ raise Exception.new(" \"What\" can\"t be an empty string")
107
+ end
108
+ parse_song_list(puts("search #{type} #{what}"))
109
+ end
110
+
111
+ def current_playlist_songs
112
+ parse_song_list(puts("playlistid"))
113
+ end
114
+
115
+ def list_all_songs
116
+ parse_song_list(puts("listallinfo"))
117
+ end
118
+
119
+ def current_song
120
+ parse_song_list(puts("currentsong"))
121
+ end
122
+
123
+ def stats
124
+ to_hash(puts("stats"))
125
+ end
126
+
127
+ def ping
128
+ song = current_song[0]
129
+ unless status[:state] == "stop"
130
+ output = {:song_time=>song[:time],:time=>status[:time].split(":").first,:artist=>song[:artist],:title=>song[:title],:file=>song[:file],:album=>song[:album],:id=>song[:id]}
131
+ else
132
+ output = {:song_time=>0,:time=>0,:artist=>nil,:title=>nil,:file=>nil,:album=>nil,:id=>nil}
133
+ end
134
+ end
135
+
136
+ def list_playlists
137
+ to_hash(puts("listplaylists"))
138
+ end
139
+
140
+ def list_playlist_info(name)
141
+ parse_song_list(puts("listplaylistinfo #{name}"))
142
+ end
143
+
144
+ def add_to_playlist(uri, name = nil)
145
+ if name.nil?
146
+ puts("add \"#{uri}\"")
147
+ else
148
+ puts("playlistadd \"#{name}\" \"#{uri}\"")
149
+ end
150
+ end
151
+
152
+ def rename_playlist(original_name, name)
153
+ puts("rename \"#{original_name}\" \"#{name}\"")
154
+ end
155
+
156
+ def create_playlist(name)
157
+ puts("save \"#{name}\"")
158
+ end
159
+
160
+ def destroy_playlist(name)
161
+ puts("rm \"#{name}\"")
162
+ end
163
+
164
+ def clear!(name = nil)
165
+ if name.nil?
166
+ puts("clear")
167
+ else
168
+ puts("playlistclear \"#{name}\"")
169
+ end
170
+ end
171
+
172
+ def get_paths
173
+ song_list(puts("listall"))
174
+ end
175
+
176
+ def list_library
177
+ root = Tree::TreeNode.new("/")
178
+ # root = Hash.new
179
+ get_paths.each do |path|
180
+ segments = path.split("/")
181
+ if root[segments.first].nil?
182
+ root << Tree::TreeNode.new(segments.first,segments.first)
183
+ # root[segments.first] = {}
184
+ end
185
+ last_element = root[segments.first]
186
+ first_element = segments.delete_at(0)
187
+ segments.each_with_index do |element, index|
188
+ if last_element[element].nil?
189
+ last_element << Tree::TreeNode.new(element, first_element + "/" + segments[0...index+1].join("/") )
190
+ # last_element[element] = {}
191
+ end
192
+ last_element = last_element[element]
193
+ end
194
+ end
195
+ root
196
+ end
197
+
198
+ def delete_song(song)
199
+ puts("delete #{song.to_s}")
200
+ end
201
+
202
+ private
203
+
204
+ def puts(command)
205
+ @socket.puts(command)
206
+ gets
207
+ end
208
+
209
+ def gets
210
+ response = ""
211
+ while line = @socket.gets do
212
+ if @@regexps["OK"].match(line)
213
+ return response
214
+ elsif error = @@regexps["ACK"].match(line)
215
+ raise Exception.new(line)
216
+ else
217
+ response << line
218
+ end
219
+ end
220
+ response
221
+ end
222
+
223
+ def status
224
+ output = puts("status")
225
+ to_hash(output)
226
+ end
227
+
228
+ def to_hash(string)
229
+ status_hash = Hash.new
230
+ string.each do |line|
231
+ key, value = line.chomp.split(": ", 2)
232
+ status_hash[key.parameterize.underscore.to_sym] = value
233
+ end
234
+ status_hash
235
+ end
236
+
237
+ def parse_song_list(song_list)
238
+ output = Array.new
239
+ song_hash = Hash.new
240
+ song_list.each do |song|
241
+ if song.match(@@regexps["FILE"])
242
+ output << song_hash
243
+ song_hash = Hash.new
244
+ end
245
+ song_hash.merge!(to_hash(song))
246
+ end
247
+ output << song_hash
248
+ output.delete_at(0)
249
+ output
250
+ end
251
+
252
+ def song_list(list)
253
+ output = Array.new
254
+ list.each do |song|
255
+ if song.match(@@regexps["FILE"])
256
+ output << song.split(": ",2).second.gsub!("\n","")
257
+ end
258
+ end
259
+ output
260
+ end
261
+
262
+ class Exception < StandardError
263
+ end
264
+ end
data/test/mpc_test.rb ADDED
@@ -0,0 +1,124 @@
1
+ require "test_helper"
2
+ class MpcTest < Test::Unit::TestCase
3
+
4
+ def setup
5
+ @mpc = Mpc.new
6
+ TCPSocket.any_instance.stubs(:puts).returns(nil)
7
+ end
8
+
9
+ test "gets raises an exception on ACK response" do
10
+ TCPSocket.any_instance.stubs(:gets).returns("ACK [5@0] {} unknown command \"asd\"\n")
11
+ assert_raise(Mpc::Exception) do
12
+ @mpc.send(:puts,'asd')
13
+ end
14
+ end
15
+
16
+ test "gets outputs empty string on OK response " do
17
+ TCPSocket.any_instance.stubs(:gets).returns("OK\n")
18
+ assert_equal("",@mpc.stop )
19
+ end
20
+
21
+ test "status outputs propper hash" do
22
+ @mpc.stubs(:gets).returns("volume: -1\nrepeat: 0\nrandom: 0\nsingle: 0\nconsume: 0\nplaylist: 43\nplaylistlength: 41\nxfade: 0\nstate: stop\nsong: 17\nsongid: 17\nnextsong: 18\nnextsongid: 18\n")
23
+ assert_equal({:songid=>"17", :state=>"stop", :single=>"0", :volume=>"-1", :nextsong=>"18", :consume=>"0", :nextsongid=>"18", :playlist=>"43", :repeat=>"0", :song=>"17", :playlistlength=>"41", :random=>"0", :xfade=>"0"},@mpc.send(:status) )
24
+ end
25
+
26
+ test "random without state should send request with opposite value" do
27
+ @mpc.stubs(:status).returns({:songid=>"17", :state=>"stop", :single=>"0", :volume=>"-1", :nextsong=>"18", :consume=>"0", :nextsongid=>"18", :playlist=>"43", :repeat=>"0", :song=>"17", :playlistlength=>"41", :random=>"0", :xfade=>"0"})
28
+ @mpc.expects(:puts).with('random 1')
29
+ @mpc.random
30
+ end
31
+
32
+ test "random with state should send request with given value" do
33
+ @mpc.stubs(:status).returns({:songid=>"17", :state=>"stop", :single=>"0", :volume=>"-1", :nextsong=>"18", :consume=>"0", :nextsongid=>"18", :playlist=>"43", :repeat=>"0", :song=>"17", :playlistlength=>"41", :random=>"0", :xfade=>"0"})
34
+ @mpc.expects(:puts).with('random 0')
35
+ @mpc.random(0)
36
+ end
37
+
38
+ test "repeat without state should send request with opposite value" do
39
+ @mpc.stubs(:status).returns({:songid=>"17", :state=>"stop", :single=>"0", :volume=>"-1", :nextsong=>"18", :consume=>"0", :nextsongid=>"18", :playlist=>"43", :repeat=>"0", :song=>"17", :playlistlength=>"41", :random=>"0", :xfade=>"0"})
40
+ @mpc.expects(:puts).with('repeat 1')
41
+ @mpc.repeat
42
+ end
43
+
44
+ test "repeat with state should send request with given value" do
45
+ @mpc.stubs(:status).returns({:songid=>"17", :state=>"stop", :single=>"0", :volume=>"-1", :nextsong=>"18", :consume=>"0", :nextsongid=>"18", :playlist=>"43", :repeat=>"0", :song=>"17", :playlistlength=>"41", :random=>"0", :xfade=>"0"})
46
+ @mpc.expects(:puts).with('repeat 0')
47
+ @mpc.repeat(0)
48
+ end
49
+
50
+ test "set_volume with volume in propper range should not raise exception" do
51
+ @mpc.expects(:puts).with('setvol 100')
52
+ @mpc.set_volume(100)
53
+ end
54
+
55
+ test "setvol with volume out of range should raise exception" do
56
+ assert_raise(Mpc::Exception) do
57
+ @mpc.set_volume(200)
58
+ end
59
+ end
60
+
61
+ test "seek without song_position seeks current song" do
62
+ @mpc.stubs(:current_song).returns({:date=>"2008", :track=>"4", :album=>"One Kind Favor", :genre=>"Blues", :time=>"190", :file=>"Kuba's Music/B.B. King - One Kind Favor/04. B.B. King - How Many More Years.mp3", :pos=>"3", :title=>"How Many More Years", :id=>"3", :albumartist=>"B.B. King", :artist=>"B.B. King"})
63
+ @mpc.expects(:puts).with('seek 3 130')
64
+ @mpc.seek(130)
65
+ end
66
+
67
+ test "seek with song_position seeks given song" do
68
+ @mpc.stubs(:current_song).returns({:date=>"2008", :track=>"4", :album=>"One Kind Favor", :genre=>"Blues", :time=>"190", :file=>"Kuba's Music/B.B. King - One Kind Favor/04. B.B. King - How Many More Years.mp3", :pos=>"3", :title=>"How Many More Years", :id=>"3", :albumartist=>"B.B. King", :artist=>"B.B. King"})
69
+ @mpc.expects(:puts).with('seek 11 20')
70
+ @mpc.seek(20,11)
71
+ end
72
+
73
+ test "find with wrong type should raise exception" do
74
+ assert_raise(Mpc::Exception) do
75
+ @mpc.find('wrong_type')
76
+ end
77
+ end
78
+
79
+ test "find with correct type but with empty string should raise exception" do
80
+ assert_raise(Mpc::Exception) do
81
+ @mpc.find('artist',"")
82
+ end
83
+ end
84
+
85
+ test "find with correct type and with string should return hash with songs" do
86
+
87
+ end
88
+
89
+ test "list_library should return tree" do
90
+ @mpc.stubs(:get_paths).returns(["Abra Dab/Miasto Jest Nasze/ABRADAB - Bezposrednio.mp3",
91
+ "Abra Dab/Miasto Jest Nasze/miasto jest nasze (3).mp3",
92
+ "iTunes/iTunes Music/02. Aaliyah/Romeo must die/06 Are You Feelin Me.mp3",
93
+ "iTunes/iTunes Music/07. Dave Bing ft. Lil' Mo/Romeo must die/12 Someone Gonna Die Tonight.mp3"])
94
+ @root = Tree::TreeNode.new('/')
95
+ @first_node = Tree::TreeNode.new('Abra Dab')
96
+
97
+ @folder = Tree::TreeNode.new('Miasto Jest Nasze')
98
+ @folder << Tree::TreeNode.new('ABRADAB - Bezposrednio.mp3')
99
+ @folder << Tree::TreeNode.new('miasto jest nasze (3).mp3')
100
+
101
+ @first_node << @folder
102
+ @root << @first_node
103
+
104
+ @second_node = Tree::TreeNode.new('iTunes')
105
+ @folder = Tree::TreeNode.new('iTunes Music')
106
+ @first_subfolder = Tree::TreeNode.new('02. Aaliyah')
107
+ @element = Tree::TreeNode.new('Romeo must die')
108
+ @mp3 = Tree::TreeNode.new('06 Are You Feelin Me.mp3')
109
+ @element << @mp3
110
+ @first_subfolder << @element
111
+ @second_subfolder = Tree::TreeNode.new("07. Dave Bing ft Lil' Mo")
112
+ @element = Tree::TreeNode.new('Romeo must die')
113
+ @mp3 = Tree::TreeNode.new('12 Someone Gonna Die Tonight.mp3')
114
+ @element << @mp3
115
+ @second_subfolder << @element
116
+
117
+ @folder << @first_subfolder
118
+ @folder << @second_subfolder
119
+ @second_node << @folder
120
+ @root << @second_node
121
+
122
+ assert_equal(@root.to_s,@mpc.list_library.to_s)
123
+ end
124
+ end
metadata ADDED
@@ -0,0 +1,67 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mpc
3
+ version: !ruby/object:Gem::Version
4
+ hash: 9
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ version: "0.1"
10
+ platform: ruby
11
+ authors:
12
+ - "Micha\xC5\x82 Krzy\xC5\xBCanowski"
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-08-09 00:00:00 +02:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: Ruby MPD client gem
22
+ email: michal.krzyzanowski+mpc@gmail.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files: []
28
+
29
+ files:
30
+ - lib/mpc.rb
31
+ - test/mpc_test.rb
32
+ has_rdoc: true
33
+ homepage:
34
+ licenses: []
35
+
36
+ post_install_message:
37
+ rdoc_options: []
38
+
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ hash: 3
47
+ segments:
48
+ - 0
49
+ version: "0"
50
+ required_rubygems_version: !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ hash: 3
56
+ segments:
57
+ - 0
58
+ version: "0"
59
+ requirements: []
60
+
61
+ rubyforge_project:
62
+ rubygems_version: 1.3.7
63
+ signing_key:
64
+ specification_version: 3
65
+ summary: MPD client gem
66
+ test_files:
67
+ - test/mpc_test.rb