rwdmpd 0.06

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 (163) hide show
  1. data/Readme.txt +475 -0
  2. data/bin/rwdmpd +19 -0
  3. data/code/01rwdcore/01rwdcore.rb +29 -0
  4. data/code/01rwdcore/02helptexthashbegin.rb +4 -0
  5. data/code/01rwdcore/03helptexthash.rb +23 -0
  6. data/code/01rwdcore/04helptextend.rb +6 -0
  7. data/code/01rwdcore/jumplinkcommand.rb +26 -0
  8. data/code/01rwdcore/openhelpwindow.rb +31 -0
  9. data/code/01rwdcore/returntomain.rb +10 -0
  10. data/code/01rwdcore/rundocuments.rb +10 -0
  11. data/code/01rwdcore/runeditconfiguration.rb +10 -0
  12. data/code/01rwdcore/runhelpabout.rb +10 -0
  13. data/code/01rwdcore/runopentinkerdocument.rb +7 -0
  14. data/code/01rwdcore/rwdtinkerversion.rb +22 -0
  15. data/code/01rwdcore/rwdwindowreturn.rb +9 -0
  16. data/code/01rwdcore/selectiontab.rb +9 -0
  17. data/code/01rwdcore/setuphelpaboutoptions.rb +13 -0
  18. data/code/01rwdcore/setuptinkerdocuments.rb +6 -0
  19. data/code/01rwdcore/test_cases.rb +109 -0
  20. data/code/01rwdcore/test_harness.rb +13 -0
  21. data/code/01rwdcore/uploadreturns.rb +62 -0
  22. data/code/dd0viewphoto/dd0viewphoto.rb +3 -0
  23. data/code/superant.com.rwdmp3/0uninstallapplet.rb +11 -0
  24. data/code/superant.com.rwdmp3/clearscreendisplay.rb +7 -0
  25. data/code/superant.com.rwdmp3/controlmpd.rb +139 -0
  26. data/code/superant.com.rwdmp3/helptexthashrwdmp3.rb +41 -0
  27. data/code/superant.com.rwdmp3/listplaylistfiles.rb +12 -0
  28. data/code/superant.com.rwdmp3/loadconfigurationrecord.rb +22 -0
  29. data/code/superant.com.rwdmp3/loadconfigurationvariables.rb +13 -0
  30. data/code/superant.com.rwdmp3/loadplaylistrecord.rb +19 -0
  31. data/code/superant.com.rwdmp3/mpd_client.rb +41 -0
  32. data/code/superant.com.rwdmp3/mpd_seek.rb +23 -0
  33. data/code/superant.com.rwdmp3/openhelpwindowrwdmp3.rb +25 -0
  34. data/code/superant.com.rwdmp3/runrwdmpdwindow.rb +10 -0
  35. data/code/superant.com.rwdmp3/rwdtinkerversion.rb +10 -0
  36. data/code/superant.com.rwdmp3/saveconfigurationrecord.rb +19 -0
  37. data/code/superant.com.rwdmp3/saveplaylistrecord.rb +18 -0
  38. data/code/superant.com.rwdmp3/startmp3server.rb +16 -0
  39. data/code/superant.com.rwdtinkerbackwindow/diagnostictab.rb +19 -0
  40. data/code/superant.com.rwdtinkerbackwindow/helptexthashtinkerwin2.rb +61 -0
  41. data/code/superant.com.rwdtinkerbackwindow/initiateapplets.rb +240 -0
  42. data/code/superant.com.rwdtinkerbackwindow/installgemapplet.rb +34 -0
  43. data/code/superant.com.rwdtinkerbackwindow/installremotegem.rb +20 -0
  44. data/code/superant.com.rwdtinkerbackwindow/listgemdirs.rb +12 -0
  45. data/code/superant.com.rwdtinkerbackwindow/listgemzips.rb +53 -0
  46. data/code/superant.com.rwdtinkerbackwindow/listinstalledfiles.rb +12 -0
  47. data/code/superant.com.rwdtinkerbackwindow/listzips.rb +33 -0
  48. data/code/superant.com.rwdtinkerbackwindow/loadconfigurationrecord.rb +22 -0
  49. data/code/superant.com.rwdtinkerbackwindow/loadconfigurationvariables.rb +14 -0
  50. data/code/superant.com.rwdtinkerbackwindow/network.rb +87 -0
  51. data/code/superant.com.rwdtinkerbackwindow/openappletname.rb +19 -0
  52. data/code/superant.com.rwdtinkerbackwindow/openhelpwindowtinkerwin2.rb +38 -0
  53. data/code/superant.com.rwdtinkerbackwindow/remotegemlist.rb +24 -0
  54. data/code/superant.com.rwdtinkerbackwindow/removeapplet.rb +46 -0
  55. data/code/superant.com.rwdtinkerbackwindow/removeappletvariables.rb +52 -0
  56. data/code/superant.com.rwdtinkerbackwindow/runremoteinstall.rb +11 -0
  57. data/code/superant.com.rwdtinkerbackwindow/runrwdtinkerbackwindow.rb +15 -0
  58. data/code/superant.com.rwdtinkerbackwindow/rwdtinkerwin2version.rb +13 -0
  59. data/code/superant.com.rwdtinkerbackwindow/saveconfigurationrecord.rb +19 -0
  60. data/code/superant.com.rwdtinkerbackwindow/viewappletcontents.rb +22 -0
  61. data/code/superant.com.rwdtinkerbackwindow/viewgemappletcontents.rb +24 -0
  62. data/code/zz0applicationend/zz0end.rb +4 -0
  63. data/configuration/language.dist +8 -0
  64. data/configuration/rwdapplicationidentity.dist +3 -0
  65. data/configuration/rwdtinker.dist +15 -0
  66. data/configuration/rwdwmpd-0.06.dist +14 -0
  67. data/configuration/tinkerwin2variables.dist +18 -0
  68. data/gui/00coreguibegin/applicationguitop.rwd +4 -0
  69. data/gui/frontwindow0/cc0openphoto.rwd +22 -0
  70. data/gui/frontwindowselections/00selectiontabbegin.rwd +11 -0
  71. data/gui/frontwindowselections/jumplinkcommands.rwd +15 -0
  72. data/gui/frontwindowselections/wwselectionend.rwd +3 -0
  73. data/gui/frontwindowtdocuments/00documentbegin.rwd +6 -0
  74. data/gui/frontwindowtdocuments/tinkerdocuments.rwd +14 -0
  75. data/gui/frontwindowtdocuments/zzdocumentend.rwd +8 -0
  76. data/gui/helpaboutbegin/zzzrwdlasttab.rwd +6 -0
  77. data/gui/helpaboutbegin/zzzzhelpscreenstart.rwd +3 -0
  78. data/gui/helpaboutbegin/zzzzzzhelpabouttab.rwd +15 -0
  79. data/gui/helpaboutzend/helpscreenend.rwd +3 -0
  80. data/gui/helpaboutzend/zhelpscreenstart2.rwd +3 -0
  81. data/gui/helpaboutzend/zzzzhelpabout2.rwd +15 -0
  82. data/gui/helpaboutzend/zzzzhelpscreen2end.rwd +3 -0
  83. data/gui/tinkerbackwindows/superant.com.rwdmp3/10appletbegin.rwd +4 -0
  84. data/gui/tinkerbackwindows/superant.com.rwdmp3/20rwdmpd.rwd +37 -0
  85. data/gui/tinkerbackwindows/superant.com.rwdmp3/25rwdseek.rwd +23 -0
  86. data/gui/tinkerbackwindows/superant.com.rwdmp3/30editplaylist.rwd +27 -0
  87. data/gui/tinkerbackwindows/superant.com.rwdmp3/88viewconfiguration.rwd +32 -0
  88. data/gui/tinkerbackwindows/superant.com.rwdmp3/89rwddiagnostics.rwd +26 -0
  89. data/gui/tinkerbackwindows/superant.com.rwdmp3/90jumplinkcommands.rwd +17 -0
  90. data/gui/tinkerbackwindows/superant.com.rwdmp3/9end.rwd +6 -0
  91. data/gui/tinkerbackwindows/superant.com.tinkerbackwindow/1appname.rwd +5 -0
  92. data/gui/tinkerbackwindows/superant.com.tinkerbackwindow/40rwdlistzips.rwd +41 -0
  93. data/gui/tinkerbackwindows/superant.com.tinkerbackwindow/45installremotezip.rwd +44 -0
  94. data/gui/tinkerbackwindows/superant.com.tinkerbackwindow/50rwdlistapplets.rwd +44 -0
  95. data/gui/tinkerbackwindows/superant.com.tinkerbackwindow/60editconfiguration.rwd +30 -0
  96. data/gui/tinkerbackwindows/superant.com.tinkerbackwindow/70rwddiagnostics.rwd +29 -0
  97. data/gui/tinkerbackwindows/superant.com.tinkerbackwindow/81jumplinkcommands.rwd +17 -0
  98. data/gui/tinkerbackwindows/superant.com.tinkerbackwindow/9backend.rwd +6 -0
  99. data/gui/tinkerbackwindows/superant.com.tinkerhelpwindow/1appname.rwd +31 -0
  100. data/gui/tinkerbackwindows/superant.com.tinkerhelpwindow/9end.rwd +4 -0
  101. data/gui/tinkerbackwindows/superant.com.versionwindow/1appname.rwd +19 -0
  102. data/gui/tinkerbackwindows/superant.com.versionwindow/helpaboutwindow.rwd +17 -0
  103. data/gui/zzcoreguiend/yy9rwdend.rwd +4 -0
  104. data/init.rb +277 -0
  105. data/installed/mpdmusicdata2.inf +2 -0
  106. data/installed/rwdwmpd-0.06.inf +10 -0
  107. data/installed/temp.rb +1 -0
  108. data/lang/en/rwdcore/languagefile.rb +58 -0
  109. data/lang/es/rwdcore/languagefile-es.rb +62 -0
  110. data/lang/fr/rwdcore/languagefile.rb +64 -0
  111. data/lang/jp/rwdcore/languagefile.rb +72 -0
  112. data/lang/nl/rwdcore/languagefile.rb +75 -0
  113. data/lib/librmpd.rb +1152 -0
  114. data/lib/mpdserver.rb +1204 -0
  115. data/lib/rconftool.rb +387 -0
  116. data/lib/rwd/browser.rb +123 -0
  117. data/lib/rwd/ftools.rb +174 -0
  118. data/lib/rwd/mime.rb +328 -0
  119. data/lib/rwd/net.rb +876 -0
  120. data/lib/rwd/ruby.rb +889 -0
  121. data/lib/rwd/rwd.rb +1422 -0
  122. data/lib/rwd/sgml.rb +236 -0
  123. data/lib/rwd/thread.rb +63 -0
  124. data/lib/rwd/tree.rb +371 -0
  125. data/lib/rwd/xml.rb +101 -0
  126. data/lib/rwdthemes/default.rwd +317 -0
  127. data/lib/rwdthemes/pda.rwd +72 -0
  128. data/lib/rwdthemes/windowslike.rwd +171 -0
  129. data/lib/zip/ioextras.rb +114 -0
  130. data/lib/zip/stdrubyext.rb +111 -0
  131. data/lib/zip/tempfile_bugfixed.rb +195 -0
  132. data/lib/zip/zip.rb +1378 -0
  133. data/lib/zip/zipfilesystem.rb +558 -0
  134. data/lib/zip/ziprequire.rb +61 -0
  135. data/music/classicalmues.mp3 +0 -0
  136. data/rwd_files/HowTo_Mpd.txt +136 -0
  137. data/rwd_files/HowTo_Tinker.txt +482 -0
  138. data/rwd_files/HowTo_TinkerWin2.txt +202 -0
  139. data/rwd_files/Readme.txt +57 -0
  140. data/rwd_files/RubyWebDialogs.html +6 -0
  141. data/rwd_files/favicon.ico +0 -0
  142. data/rwd_files/rdoc-style.css +175 -0
  143. data/rwd_files/rwdapplications.html +54 -0
  144. data/rwd_files/tinker.png +0 -0
  145. data/rwdconfig.dist +22 -0
  146. data/rwdmpd.rb +1 -0
  147. data/tests/RubyGauge.rb +179 -0
  148. data/tests/checkdepends.sh +4 -0
  149. data/tests/cleancnf.sh +6 -0
  150. data/tests/makedist-rwdwmpd.rb +58 -0
  151. data/tests/makedist.rb +66 -0
  152. data/tests/rdep.rb +354 -0
  153. data/tests/totranslate.lang +93 -0
  154. data/zips/rwdwaddresses-1.06.zip +0 -0
  155. data/zips/rwdwcalc-0.62.zip +0 -0
  156. data/zips/rwdwfoldeditor-0.04.zip +0 -0
  157. data/zips/rwdwgutenberg-0.09.zip +0 -0
  158. data/zips/rwdwmpd-0.06.zip +0 -0
  159. data/zips/rwdwruby-1.07.zip +0 -0
  160. data/zips/temp.rb +1 -0
  161. data/zips/tinkerbellw-0.02.zip +0 -0
  162. data/zips/wrubyslippers-1.06.zip +0 -0
  163. metadata +220 -0
@@ -0,0 +1,1204 @@
1
+ #
2
+ #== mpdserver.rb
3
+ #
4
+ # This is the test server for librmpd. It is a 'shallow' server,
5
+ # it implements only the client/server protocol in a highly
6
+ # scriptable manner. This means you can set up your own simple
7
+ # test music database for testing an mpd client. You can now
8
+ # distribute your unit tests (you do have unit tests, yes?) along
9
+ # with a test database (a YAML file), and anyone can check that
10
+ # your client is in working order.
11
+ #
12
+ #== Usage
13
+ #
14
+ # The MPD Server is a subclass of GServer, so you have a lot of
15
+ # flexibility at your disposal. The constructor of the server object
16
+ # takes the port, an optional YAML database file, and any args for GServer.
17
+ #
18
+ # The YAML database file can be one of your own creation, or you can use
19
+ # one supplied by librmpd (default)
20
+ #
21
+ # Example:
22
+ #
23
+ # require 'rubygems'
24
+ # require 'librmpd'
25
+ # require 'mpdserver'
26
+ #
27
+ # server = MPDTestServer.new 7700
28
+ # server.start
29
+ #
30
+ # You can then enable auditing to see what commands are run by a client:
31
+ #
32
+ # server.audit = true
33
+ #
34
+ # This will print any commands from a client to stdout
35
+ #
36
+ #=== Unit Testing
37
+ #
38
+ # For unit testing a client using the test server, I recommend using the
39
+ # set up and tear down methods to initialize and destroy a test server.
40
+ #
41
+ # def setup
42
+ # @server = MPDTestServer.new 7700
43
+ # @server.start
44
+ # end
45
+ #
46
+ # def teardown
47
+ # @server.stop
48
+ # end
49
+ #
50
+ # This will ensure you are using a clean server instance for each test.
51
+
52
+ require 'gserver'
53
+ require 'yaml'
54
+
55
+ class MPDTestServer < GServer
56
+
57
+ def initialize( port, db_file = nil, *args )
58
+ super port, *args
59
+
60
+ if db_file.nil?
61
+ db_file = __FILE__.gsub(/\/[^\/]*$/, '') + '/../data/database.yaml'
62
+ end
63
+
64
+ @status = {
65
+ :volume => 0,
66
+ :repeat => 0,
67
+ :random => 0,
68
+ :playlist => 1,
69
+ :state => 'stop',
70
+ :xfade => 0
71
+ }
72
+ @elapsed_time = 0
73
+ @current_song = nil
74
+ @database = YAML::load( File.open( db_file ) )
75
+ @songs = @database[0]
76
+ @playlists = @database[1]
77
+ @artists = []
78
+ @albums = []
79
+ @titles = []
80
+ @the_playlist = []
81
+ @playback_thread = nil
82
+ @filetree = {:name =>'', :dirs =>[], :songs =>[]}
83
+ @songs.each_with_index do |song,i|
84
+ song['id'] = i
85
+ if !song['artist'].nil? and !@artists.include? song['artist']
86
+ @artists << song['artist']
87
+ end
88
+ if !song['album'].nil? and !@albums.include? song['album']
89
+ @albums << song['album']
90
+ end
91
+ if !song['title'].nil?
92
+ @titles << song['title']
93
+ end
94
+ if !song['file'].nil?
95
+ dirs = song['file'].split '/'
96
+ dirs.pop
97
+ the_dir = @filetree
98
+ dirs.each do |d|
99
+ found = nil
100
+ the_dir[:dirs].each do |sub|
101
+ if sub[:name] == d
102
+ found = sub
103
+ break
104
+ end
105
+ end
106
+ if found.nil?
107
+ found = {:name => d, :dirs =>[], :songs =>[]}
108
+ the_dir[:dirs] << found
109
+ end
110
+ the_dir = found
111
+ end # End dirs.each
112
+ the_dir[:songs] << song
113
+ end # End if !song['file'].nil?
114
+ end # End @songs.each
115
+
116
+ sort_dir @filetree
117
+ @artists.sort!
118
+ @albums.sort!
119
+ @titles.sort!
120
+ end
121
+
122
+ def start
123
+ super
124
+
125
+ @playback_thread = Thread.new(@status, self) do |status, server|
126
+ while not server.stopped?
127
+ if status[:state] == 'play'
128
+ song = server.get_current_song
129
+ if song.nil?
130
+ server.elapsed_time = 0
131
+ status[:state] = 'stop'
132
+ next
133
+ end
134
+
135
+ status[:time] = "#{server.elapsed_time}:#{song['time']}"
136
+ status[:bitrate] = 192
137
+ status[:audio] = '44100:16:2'
138
+
139
+ if server.elapsed_time >= song['time'].to_i
140
+ server.elapsed_time = 0
141
+ server.next_song
142
+ end
143
+
144
+ server.elapsed_time = server.elapsed_time + 1
145
+ elsif status[:state] == 'pause'
146
+ song = server.get_current_song
147
+ if song.nil?
148
+ server.elapsed_time = 0
149
+ status[:state] = 'stop'
150
+ next
151
+ end
152
+ status[:time] = "#{server.elapsed_time}:#{song['time']}"
153
+ status[:bitrate] = 192
154
+ status[:audio] = '44100:16:2'
155
+ else
156
+ status[:time] = nil
157
+ status[:bitrate] = nil
158
+ status[:audio] = nil
159
+ server.elapsed_time = 0
160
+ end
161
+ sleep 1
162
+ end
163
+ end
164
+ end
165
+
166
+ def serve( sock )
167
+ command_list = []
168
+ in_cmd_list = false
169
+ in_ok_list = false
170
+ the_error = nil
171
+ sock.puts 'OK MPD 0.11.5'
172
+ begin
173
+ while line = sock.gets
174
+
175
+ args = build_args line
176
+
177
+ cmd = args.shift
178
+
179
+ if cmd == 'command_list_begin' and args.length == 0 and !in_cmd_list
180
+ in_cmd_list = true
181
+ log 'MPD: Starting Command List' if audit
182
+ elsif cmd == 'command_list_ok_begin' and args.length == 0 and !in_cmd_list
183
+ in_cmd_list = true
184
+ in_ok_list = true
185
+ log 'MPD: Starting Command OK List' if audit
186
+ elsif cmd == 'command_list_end' and in_cmd_list
187
+ log 'MPD: Running Command List' if audit
188
+
189
+ the_ret = true
190
+ command_list.each_with_index do |set,i|
191
+ the_ret = do_cmd sock, set[0], set[1]
192
+
193
+ if audit
194
+ log "MPD Command List: CMD ##{i}: \"#{set[0]}(#{set[1].join(', ')})\": " + (the_ret ? 'successful' : 'failed')
195
+ end
196
+
197
+ break unless the_ret
198
+
199
+ sock.puts 'list_OK' if in_ok_list
200
+
201
+ end
202
+
203
+ sock.puts 'OK' if the_ret
204
+
205
+ command_list.clear
206
+ in_cmd_list = false
207
+ in_ok_list = false
208
+ else
209
+ if in_cmd_list
210
+ command_list << [cmd, args]
211
+ else
212
+ ret = do_cmd sock, cmd, args
213
+ sock.puts 'OK' if ret
214
+ if audit
215
+ log "MPD Command \"#{cmd}(#{args.join(', ')})\": " + (ret ? 'successful' : 'failed')
216
+ end # End if audit
217
+ end # End if in_cmd_list
218
+ end # End if cmd == 'comand_list_begin' ...
219
+ end # End while line = sock.gets
220
+ rescue
221
+ end
222
+ end
223
+
224
+ def do_cmd( sock, cmd, args )
225
+ case cmd
226
+ when 'add'
227
+ if args.length == 0
228
+ # Add the entire database
229
+ @songs.each do |s|
230
+ s['_mod_ver'] = @status[:playlist]
231
+ incr_version
232
+ @the_playlist << s
233
+ end
234
+ return true
235
+ else
236
+ # Add a single entry
237
+ the_song = nil
238
+ @songs.each do |s|
239
+ if s['file'] == args[0]
240
+ the_song = s
241
+ break
242
+ end
243
+ end
244
+
245
+ if the_song.nil?
246
+ dir = locate_dir(args[0])
247
+ if not dir.nil?
248
+ # Add the dir
249
+ add_dir_to_pls dir
250
+ return true
251
+ else
252
+ return(cmd_fail(sock,'ACK [50@0] {add} directory or file not found'))
253
+ end
254
+ else
255
+ the_song['_mod_ver'] = @status[:playlist]
256
+ incr_version
257
+ @the_playlist << the_song
258
+ return true
259
+ end
260
+ end
261
+ when 'clear'
262
+ args_check( sock, cmd, args, 0 ) do
263
+ incr_version
264
+ @the_playlist = []
265
+ @current_song = nil
266
+ return true
267
+ end
268
+ when 'clearerror'
269
+ args_check( sock, cmd, args, 0 ) do
270
+ the_error = nil
271
+ return true
272
+ end
273
+ when 'close'
274
+ sock.close
275
+ return true
276
+ when 'crossfade'
277
+ args_check( sock, cmd, args, 1 ) do |args|
278
+ if is_int(args[0]) and args[0].to_i >= 0
279
+ @status[:xfade] = args[0].to_i
280
+ return true
281
+ else
282
+ return(cmd_fail(sock,"ACK [2@0] {crossfade} \"#{args[0]}\" is not a integer >= 0"))
283
+ end
284
+ end
285
+ when 'currentsong'
286
+ args_check( sock, cmd, args, 0 ) do
287
+ if @current_song != nil and @current_song < @the_playlist.length
288
+ send_song sock, @the_playlist[@current_song]
289
+ end
290
+ return true
291
+ end
292
+ when 'delete'
293
+ args_check( sock, cmd, args, 1 ) do |args|
294
+ if is_int args[0]
295
+ if args[0].to_i < 0 or args[0].to_i >= @the_playlist.length
296
+ return(cmd_fail(sock,"ACK [50@0] {delete} song doesn't exist: \"#{args[0]}\""))
297
+ else
298
+ @the_playlist.delete_at args[0].to_i
299
+ args[0].to_i.upto @the_playlist.length - 1 do |i|
300
+ @the_playlist[i]['_mod_ver'] = @status[:playlist]
301
+ end
302
+ incr_version
303
+ return true
304
+ end
305
+ else
306
+ return(cmd_fail('ACK [2@0] {delete} need a positive integer'))
307
+ end
308
+ end
309
+ when 'deleteid'
310
+ args_check( sock, cmd, args, 1 ) do |args|
311
+ if is_int args[0]
312
+ the_song = nil
313
+ @the_playlist.each do |song|
314
+ if song['id'] == args[0].to_i
315
+ the_song = song
316
+ break
317
+ end
318
+ end
319
+
320
+ if not the_song.nil?
321
+ index = @the_playlist.index the_song
322
+ @the_playlist.delete the_song
323
+ index.upto @the_playlist.length - 1 do |i|
324
+ @the_playlist[i]['_mod_ver'] = @status[:playlist]
325
+ end
326
+ incr_version
327
+ return true
328
+ else
329
+ return(cmd_fail(sock,"ACK [50@0] {deleteid} song id doesn't exist: \"#{args[0]}\""))
330
+ end
331
+ else
332
+ return(cmd_fail(sock,'ACK [2@0] {deleteid} need a positive integer'))
333
+ end
334
+ end
335
+ when 'find'
336
+ args_check( sock, cmd, args, 2 ) do |args|
337
+ if args[0] != 'album' and args[0] != 'artist' and args[0] != 'title'
338
+ return(cmd_fail(sock,'ACK [2@0] {find} incorrect arguments'))
339
+ else
340
+ if args[0] == 'album'
341
+ @songs.each do |song|
342
+ if song['album'] == args[1]
343
+ send_song sock, song
344
+ end
345
+ end
346
+ elsif args[0] == 'artist'
347
+ @songs.each do |song|
348
+ if song['artist'] == args[1]
349
+ send_song sock, song
350
+ end
351
+ end
352
+ elsif args[0] == 'title'
353
+ @songs.each do |song|
354
+ if song['title'] == args[1]
355
+ send_song sock, song
356
+ end
357
+ end
358
+ end
359
+ return true
360
+ end
361
+ end
362
+ when 'kill'
363
+ args_check( sock, cmd, args, 0 ) do
364
+ sock.close
365
+ return true
366
+ end
367
+ when 'list'
368
+ args_check( sock, cmd, args, 1..2 ) do |args|
369
+ if args[0] != 'album' and args[0] != 'artist' and args[0] != 'title'
370
+ return(cmd_fail(sock,"ACK [2@0] {list} \"#{args[0]}\" is not known"))
371
+ elsif args[0] == 'artist' and args.length > 1
372
+ return(cmd_fail(sock,'ACK [2@0] {list} should be "Album" for 3 arguments'))
373
+ else
374
+ if args[0] == 'artist'
375
+ # List all Artists
376
+ @artists.each do |artist|
377
+ sock.puts "Artist: #{artist}"
378
+ end
379
+ return true
380
+ elsif args[0] == 'title'
381
+ # List all Titles
382
+ @titles.each do |title|
383
+ sock.puts "Title: #{title}"
384
+ end
385
+ return true
386
+ else
387
+ if args.length == 2
388
+ # List all Albums by Artist
389
+ # artist == args[1]
390
+ listed = []
391
+ @songs.each do |song|
392
+ if song['artist'] == args[1]
393
+ if not song['album'].nil? and !listed.include? song['album']
394
+ sock.puts "Album: #{song['album']}"
395
+ listed << song['album']
396
+ end
397
+ end
398
+ end
399
+ return true
400
+ else
401
+ # List all Albums
402
+ @albums.each do |album|
403
+ sock.puts "Album: #{album}"
404
+ end
405
+ return true
406
+ end
407
+ end
408
+ end
409
+ end
410
+ when 'listall'
411
+ args_check( sock, cmd, args, 0..1 ) do |args|
412
+ if args.length == 0
413
+ @filetree[:dirs].each do |d|
414
+ send_dir sock, d, false
415
+ end
416
+ else
417
+ was_song = false
418
+ @songs.each do |song|
419
+ if song['file'] == args[0]
420
+ sock.puts "file: #{song['file']}"
421
+ was_song = true
422
+ break
423
+ end
424
+ end
425
+
426
+ if was_song
427
+ return true
428
+ end
429
+
430
+ dir = locate_dir args[0]
431
+ if not dir.nil?
432
+ parents = args[0].split '/'
433
+ parents.pop
434
+ parents = parents.join '/'
435
+ parents += '/' unless parents.length == 0
436
+ send_dir sock, dir, false, parents
437
+ else
438
+ return(cmd_fail(sock,'ACK [50@0] {listall} directory or file not found'))
439
+ end
440
+ end
441
+ return true
442
+ end
443
+ when 'listallinfo'
444
+ args_check( sock, cmd, args, 0..1 ) do |args|
445
+ if args.length == 0
446
+ @filetree[:dirs].each do |d|
447
+ send_dir sock, d, true
448
+ end
449
+ else
450
+ was_song = false
451
+ @songs.each do |song|
452
+ if song['file'] == args[0]
453
+ send_song song
454
+ was_song = true
455
+ break
456
+ end
457
+ end
458
+
459
+ if was_song
460
+ return true
461
+ end
462
+
463
+ dir = locate_dir args[0]
464
+ if not dir.nil?
465
+ parents = args[0].split '/'
466
+ parents.pop
467
+ parents = parents.join '/'
468
+ parents += '/' unless parents.length == 0
469
+ send_dir sock, dir, true, parents
470
+ else
471
+ return(cmd_fail(sock,'ACK [50@0] {listallinfo} directory or file not found'))
472
+ end
473
+ end
474
+ return true
475
+ end
476
+ when 'load'
477
+ args_check( sock, cmd, args, 1 ) do
478
+ # incr_version for each song loaded
479
+ pls = args[0] + '.m3u'
480
+ the_pls = nil
481
+ @playlists.each do |p|
482
+ if p['file'] == pls
483
+ the_pls = p
484
+ break
485
+ end
486
+ end
487
+
488
+ unless the_pls.nil?
489
+ the_pls['songs'].each do |song|
490
+ song['_mod_ver'] = @status[:playlist]
491
+ @the_playlist << song
492
+ incr_version
493
+ end
494
+ else
495
+ return(cmd_fail(sock,"ACK [50@0] {load} playlist \"#{args[0]}\" not found"))
496
+ end
497
+ end
498
+ when 'lsinfo'
499
+ args_check( sock, cmd, args, 0..1 ) do
500
+ if args.length == 0
501
+ @filetree[:dirs].each do |d|
502
+ sock.puts "directory: #{d[:name]}"
503
+ d[:songs].each do |s|
504
+ send_song sock, s
505
+ end
506
+ end
507
+ @playlists.each do |pls|
508
+ sock.puts "playlist: #{pls['file'].gsub( /\.m3u$/, '' )}"
509
+ end
510
+ else
511
+ dir = locate_dir args[0]
512
+ if dir.nil?
513
+ return(cmd_fail(sock,"ACK [50@0] {lsinfo} directory not found"))
514
+ else
515
+ dir[:dirs].each do |d|
516
+ sock.puts "directory: #{args[0] + '/' + d[:name]}"
517
+ end
518
+ dir[:songs].each do |s|
519
+ send_song sock, s
520
+ end
521
+ end
522
+ end
523
+ return true
524
+ end
525
+ when 'move'
526
+ args_check( sock, cmd, args, 2 ) do |args|
527
+ if !is_int args[0]
528
+ return(cmd_fail(sock,"ACK [2@0] {move} \"#{args[0]}\" is not a integer"))
529
+ elsif !is_int args[1]
530
+ return(cmd_fail(sock,"ACK [2@0] {move} \"#{args[1]}\" is not a integer"))
531
+ elsif args[0].to_i < 0 or args[0].to_i >= @the_playlist.length
532
+ return(cmd_fail(sock,"ACK [50@0] {move} song doesn't exist: \"#{args[0]}\""))
533
+ elsif args[1].to_i < 0 or args[1].to_i >= @the_playlist.length
534
+ return(cmd_fail(sock,"ACK [50@0] {move} song doesn't exist: \"#{args[1]}\""))
535
+ else
536
+ tmp = @the_playlist.delete_at args[0].to_i
537
+ @the_playlist.insert args[1].to_i, tmp
538
+ if args[0].to_i < args[1].to_i
539
+ args[0].to_i.upto args[1].to_i do |i|
540
+ @the_playlist[i]['_mod_ver'] = @status[:playlist]
541
+ end
542
+ else
543
+ args[1].to_i.upto args[0].to_i do |i|
544
+ @the_playlist[i]['_mod_ver'] = @status[:playlist]
545
+ end
546
+ end
547
+ incr_version
548
+ return true
549
+ end
550
+ end
551
+ when 'moveid'
552
+ args_check( sock, cmd, args, 2 ) do |args|
553
+ if !is_int args[0]
554
+ return(cmd_fail(sock,"ACK [2@0] {moveid} \"#{args[0]}\" is not a integer"))
555
+ elsif !is_int args[1]
556
+ return(cmd_fail(sock,"ACK [2@0] {moveid} \"#{args[1]}\" is not a integer"))
557
+ elsif args[1].to_i < 0 or args[1].to_i >= @the_playlist.length
558
+ return(cmd_fail(sock,"ACK [50@0] {moveid} song doesn't exist: \"#{args[1]}\""))
559
+ else
560
+ # Note: negative args should be checked
561
+ the_song = nil
562
+ index = -1
563
+ @the_playlist.each_with_index do |song,i|
564
+ if song['id'] == args[0].to_i
565
+ the_song = song
566
+ index = i
567
+ end
568
+ end
569
+ if the_song.nil?
570
+ return(cmd_fail(sock,"ACK [50@0] {moveid} song id doesn't exist: \"#{args[0]}\""))
571
+ end
572
+ tmp = @the_playlist.delete_at index
573
+ @the_playlist.insert args[1].to_i, tmp
574
+ if index < args[1].to_i
575
+ index.upto args[1].to_i do |i|
576
+ @the_playlist[i]['_mod_ver'] = @status[:playlist]
577
+ end
578
+ else
579
+ args[1].to_i.upto index do |i|
580
+ @the_playlist[i]['_mod_ver'] = @status[:playlist]
581
+ end
582
+ end
583
+ incr_version
584
+ return true
585
+ end
586
+ end
587
+ when 'next'
588
+ args_check( sock, cmd, args, 0 ) do
589
+ if @status[:state] != 'stop'
590
+ next_song
591
+ @elapsed_time = 0
592
+ @status[:state] = 'play'
593
+ end
594
+ return true
595
+ end
596
+ when 'pause'
597
+ args_check( sock, cmd, args, 0..1 ) do |args|
598
+ if args.length > 0 and not is_bool args[0]
599
+ return(cmd_fail(sock,"ACK [2@0] {pause} \"#{args[0]}\" is not 0 or 1"))
600
+ end
601
+
602
+ if @status[:state] != 'stop'
603
+ if args.length == 1
604
+ @status[:state] = ( args[0] == '1' ? 'pause' : 'play' )
605
+ else
606
+ @status[:state] = ( @status[:state] == 'pause' ? 'play' : 'pause' )
607
+ end
608
+ end
609
+
610
+ return true
611
+ end
612
+ when 'password'
613
+ args_check( sock, cmd, args, 1 ) do |args|
614
+ return true if args[0] == 'test'
615
+ return(cmd_fail(sock,"ACK [3@0] {password} incorrect password"))
616
+ end
617
+ when 'ping'
618
+ args_check( sock, cmd, args, 0 ) do
619
+ return true
620
+ end
621
+ when 'play'
622
+ args_check( sock, cmd, args, 0..1 ) do |args|
623
+ if args.length > 0 and !is_int(args[0])
624
+ return(cmd_fail(sock,'ACK [2@0] {play} need a positive integer'))
625
+ else
626
+ args.clear if args[0] == '-1'
627
+ if args.length == 0
628
+ if @the_playlist.length > 0 and @status[:state] != 'play'
629
+ @current_song = 0 if @current_song.nil?
630
+ @elapsed_time = 0
631
+ @status[:state] = 'play'
632
+ end
633
+ else
634
+ if args[0].to_i < 0 or args[0].to_i >= @the_playlist.length
635
+ return(cmd_fail(sock,"ACK [50@0] {play} song doesn't exist: \"#{args[0]}\""))
636
+ end
637
+
638
+ @current_song = args[0].to_i
639
+ @elapsed_time = 0
640
+ @status[:state] = 'play'
641
+ end
642
+ return true
643
+ end
644
+ end
645
+ when 'playid'
646
+ args_check( sock, cmd, args, 0..1 ) do |args|
647
+ if args.length > 0 and !is_int(args[0])
648
+ return(cmd_fail(sock,'ACK [2@0] {playid} need a positive integer'))
649
+ else
650
+ args.clear if args[0] == '-1'
651
+ if args.length == 0
652
+ if @the_playlist.length > 0 and @status[:state] != 'play'
653
+ @current_song = 0 if @current_song.nil?
654
+ @elapsed_time = 0
655
+ @status[:state] = 'play'
656
+ end
657
+ else
658
+ index = nil
659
+ @the_playlist.each_with_index do |s,i|
660
+ if s['id'] == args[0].to_i
661
+ index = i
662
+ break;
663
+ end
664
+ end
665
+
666
+ return(cmd_fail(sock,"ACK [50@0] {playid} song id doesn't exist: \"#{args[0]}\"")) if index.nil?
667
+
668
+ @current_song = index
669
+ @elapsed_time = 0
670
+ @status[:state] = 'play'
671
+ end
672
+ return true
673
+ end
674
+ end
675
+ when 'playlist'
676
+ log 'MPD Warning: Call to Deprecated API: "playlist"' if audit
677
+ args_check( sock, cmd, args, 0 ) do
678
+ @the_playlist.each_with_index do |v,i|
679
+ sock.puts "#{i}:#{v['file']}"
680
+ end
681
+ return true
682
+ end
683
+ when 'playlistinfo'
684
+ args_check( sock, cmd, args, 0..1 ) do |args|
685
+ if args.length > 0 and !is_int(args[0])
686
+ return(cmd_fail(sock,'ACK [2@0] {playlistinfo} need a positive integer'))
687
+ else
688
+ args.clear if args.length > 0 and args[0].to_i < 0
689
+ if args.length != 0
690
+ if args[0].to_i >= @the_playlist.length
691
+ return(cmd_fail(sock,"ACK [50@0] {playlistinfo} song doesn't exist: \"#{args[0]}\""))
692
+ else
693
+ song = @the_playlist[args[0].to_i]
694
+ send_song sock, song
695
+ sock.puts "Pos: #{args[0].to_i}"
696
+ return true
697
+ end
698
+ else
699
+ @the_playlist.each_with_index do |song,i|
700
+ send_song sock, song
701
+ sock.puts "Pos: #{i}"
702
+ end
703
+ return true
704
+ end
705
+ end
706
+ end
707
+ when 'playlistid'
708
+ args_check( sock, cmd, args, 0..1 ) do |args|
709
+ if args.length > 0 and !is_int(args[0])
710
+ return(cmd_fail(sock,'ACK [2@0] {playlistid} need a positive integer'))
711
+ else
712
+ song = nil
713
+ pos = nil
714
+ args.clear if args[0].to_i < 0
715
+ if args.length != 0
716
+ @the_playlist.each_with_index do |s,i|
717
+ if s['id'] == args[0].to_i
718
+ song = s
719
+ pos = i
720
+ break;
721
+ end
722
+ end
723
+
724
+ return(cmd_fail(sock,"ACK [50@0] {playlistid} song id doesn't exist: \"#{args[0]}\"")) if song.nil?
725
+
726
+ send_song sock, song
727
+ sock.puts "Pos: #{pos}"
728
+ return true
729
+ else
730
+ @the_playlist.each_with_index do |song,i|
731
+ send_song sock, song
732
+ sock.puts "Pos: #{i}"
733
+ end
734
+ return true
735
+ end
736
+ end
737
+ end
738
+ when 'plchanges'
739
+ args_check( sock, cmd, args, 1 ) do |args|
740
+ if args.length > 0 and !is_int(args[0])
741
+ return(cmd_fail(sock,'ACK [2@0] {plchanges} need a positive integer'))
742
+ else
743
+ # Note: args[0] < 0 just return OK...
744
+ @the_playlist.each_with_index do |song,i|
745
+ if args[0].to_i > @status[:playlist] or song['_mod_ver'] >= args[0].to_i or song['_mod_ver'] == 0
746
+ send_song sock, song
747
+ sock.puts "Pos: #{i}"
748
+ end
749
+ end
750
+ return true
751
+ end
752
+ end
753
+ when 'plchangesposid'
754
+ args_check( sock, cmd, args, 1 ) do |args|
755
+ if args.length > 0 and !is_int(args[0])
756
+ return(cmd_fail(sock,'ACK [2@0] {plchangesposid} need a positive integer'))
757
+ else
758
+ # Note: args[0] < 0 just return OK...
759
+ @the_playlist.each_with_index do |song,i|
760
+ if args[0].to_i > @status[:playlist] or song['_mod_ver'] >= args[0].to_i or song['_mod_ver'] == 0
761
+ sock.puts "cpos: #{i}"
762
+ sock.puts "Id: #{song['id']}"
763
+ end
764
+ end
765
+ return true
766
+ end
767
+ end
768
+ when 'previous'
769
+ args_check( sock, cmd, args, 0 ) do
770
+ return true if @status[:state] == 'stop'
771
+ prev_song
772
+ @elapsed_time = 0
773
+ @status[:state] = 'play'
774
+ return true
775
+ end
776
+ when 'random'
777
+ args_check( sock, cmd, args, 1 ) do |args|
778
+ if is_bool args[0]
779
+ @status[:random] = args[0].to_i
780
+ return true
781
+ elsif is_int args[0]
782
+ return(cmd_fail(sock,"ACK [2@0] {random} \"#{args[0]}\" is not 0 or 1"))
783
+ else
784
+ return(cmd_fail(sock,'ACK [2@0] {random} need an integer'))
785
+ end
786
+ end
787
+ when 'repeat'
788
+ args_check( sock, cmd, args, 1 ) do |args|
789
+ if is_bool args[0]
790
+ @status[:repeat] = args[0].to_i
791
+ return true
792
+ elsif is_int args[0]
793
+ return(cmd_fail(sock,"ACK [2@0] {repeat} \"#{args[0]}\" is not 0 or 1"))
794
+ else
795
+ return(cmd_fail(sock,'ACK [2@0] {repeat} need an integer'))
796
+ end
797
+ end
798
+ when 'rm'
799
+ args_check( sock, cmd, args, 1 ) do |args|
800
+ rm_pls = args[0] + '.m3u'
801
+ the_pls = -1
802
+ @playlists.each_with_index do |pls,i|
803
+ the_pls = i if pls['file'] == rm_pls
804
+ end
805
+
806
+ if the_pls != -1
807
+ @playlists.delete_at the_pls
808
+ return true
809
+ else
810
+ return(cmd_fail(sock,"ACK [50@0] {rm} playlist \"#{args[0]}\" not found"))
811
+ end
812
+ end
813
+ when 'save'
814
+ args_check( sock, cmd, args, 1 ) do |args|
815
+ new_playlist = {'file' => args[0]+'.m3u', 'songs' => @the_playlist}
816
+ @playlists << new_playlist
817
+ return true
818
+ end
819
+ when 'search'
820
+ args_check( sock, cmd, args, 2 ) do |args|
821
+ if args[0] != 'title' and args[0] != 'artist' and args[0] != 'album' and args[0] != 'filename'
822
+ return(cmd_fail(sock,'ACK [2@0] {search} incorrect arguments'))
823
+ end
824
+ args[0] = 'file' if args[0] == 'filename'
825
+ @songs.each do |song|
826
+ data = song[args[0]]
827
+ if not data.nil? and data.downcase.include? args[1]
828
+ send_song sock, song
829
+ end
830
+ end
831
+ return true
832
+ end
833
+ when 'seek'
834
+ args_check( sock, cmd, args, 2 ) do |args|
835
+ if !is_int args[0]
836
+ return(cmd_fail(sock,"ACK [2@0] {seek} \"#{args[0]}\" is not a integer"))
837
+ elsif !is_int args[1]
838
+ return(cmd_fail(sock,"ACK [2@0] {seek} \"#{args[1]}\" is not a integer"))
839
+ else
840
+ if args[0].to_i > @the_playlist.length or args[0].to_i < 0
841
+ return(cmd_fail(sock,"ACK [50@0] {seek} song doesn't exist: \"#{args[0]}\""))
842
+ end
843
+ args[1] = '0' if args[1].to_i < 0
844
+ song = @the_playlist[args[0].to_i]
845
+ if args[1].to_i >= song['time'].to_i
846
+ if args[0].to_i + 1 < @the_playlist.length
847
+ @current_song = args[0].to_i + 1
848
+ @elapsed_time = 0
849
+ @status[:state] = 'play' unless @status[:state] == 'pause'
850
+ else
851
+ @current_song = nil
852
+ @elapsed_time = 0
853
+ @status[:state] = 'stop'
854
+ end
855
+ else
856
+ @current_song = args[0].to_i
857
+ @elapsed_time = args[1].to_i
858
+ @status[:state] = 'play' unless @status[:state] == 'pause'
859
+ end
860
+ return true
861
+ end
862
+ end
863
+ when 'seekid'
864
+ args_check( sock, cmd, args, 2 ) do |args|
865
+ if !is_int args[0]
866
+ return(cmd_fail(sock,"ACK [2@0] {seekid} \"#{args[0]}\" is not a integer"))
867
+ elsif !is_int args[1]
868
+ return(cmd_fail(sock,"ACK [2@0] {seekid} \"#{args[1]}\" is not a integer"))
869
+ else
870
+ pos = nil
871
+ song = nil
872
+ @the_playlist.each_with_index do |s,i|
873
+ if s['id'] == args[0].to_i
874
+ song = s
875
+ pos = i
876
+ break;
877
+ end
878
+ end
879
+
880
+ if song.nil?
881
+ return(cmd_fail(sock,"ACK [50@0] {seekid} song id doesn't exist: \"#{args[0]}\""))
882
+ end
883
+
884
+ args[1] = '0' if args[1].to_i < 0
885
+ if args[1].to_i >= song['time'].to_i
886
+ if pos + 1 < @the_playlist.length
887
+ @current_song = pos + 1
888
+ @elapsed_time = 0
889
+ @status[:state] = 'play' unless @status[:state] == 'pause'
890
+ else
891
+ @current_song = nil
892
+ @elapsed_time = 0
893
+ @status[:state] = 'stop'
894
+ end
895
+ else
896
+ @current_song = pos
897
+ @elapsed_time = args[1].to_i
898
+ @status[:state] = 'play' unless @status[:state] == 'pause'
899
+ end
900
+ return true
901
+ end
902
+ end
903
+ when 'setvol'
904
+ args_check( sock, cmd, args, 1 ) do |args|
905
+ if !is_int args[0]
906
+ return(cmd_fail(sock,'ACK [2@0] {setvol} need an integer'))
907
+ else
908
+ # Note: args[0] < 0 actually sets the vol val to < 0
909
+ @status[:volume] = args[0].to_i
910
+ return true
911
+ end
912
+ end
913
+ when 'shuffle'
914
+ args_check( sock, cmd, args, 0 ) do
915
+ @the_playlist.each do |s|
916
+ s['_mod_ver'] = @status[:playlist]
917
+ end
918
+ incr_version
919
+ @the_playlist.reverse!
920
+ return true
921
+ end
922
+ when 'stats'
923
+ args_check( sock, cmd, args, 0 ) do
924
+ # artists
925
+ sock.puts "artists: #{@artists.size}"
926
+ # albums
927
+ sock.puts "albums: #{@albums.size}"
928
+ # songs
929
+ sock.puts "songs: #{@songs.size}"
930
+ # uptime
931
+ sock.puts "uptime: 500"
932
+ # db_playtime
933
+ time = 0
934
+ @songs.each do |s|
935
+ time += s['time'].to_i
936
+ end
937
+ sock.puts "db_playtime: #{time}"
938
+ # db_update
939
+ sock.puts "db_update: 1159418502"
940
+ # playtime
941
+ sock.puts "playtime: 10"
942
+ return true
943
+ end
944
+ when 'status'
945
+ args_check( sock, cmd, args, 0 ) do
946
+ @status.each_pair do |key,val|
947
+ sock.puts "#{key}: #{val}" unless val.nil?
948
+ end
949
+ sock.puts "playlistlength: #{@the_playlist.length}"
950
+
951
+ if @current_song != nil and @the_playlist.length > @current_song
952
+ sock.puts "song: #{@current_song}"
953
+ sock.puts "songid: #{@the_playlist[@current_song]['id']}"
954
+ end
955
+
956
+ @status[:updating_db] = nil
957
+ return true
958
+ end
959
+ when 'stop'
960
+ args_check( sock, cmd, args, 0 ) do
961
+ @status[:state] = 'stop'
962
+ @status[:time] = nil
963
+ @status[:bitrate] = nil
964
+ @status[:audio] = nil
965
+ return true
966
+ end
967
+ when 'swap'
968
+ args_check( sock, cmd, args, 2 ) do |args|
969
+ if !is_int args[0]
970
+ return(cmd_fail(sock,"ACK [2@0] {swap} \"#{args[0]}\" is not a integer"))
971
+ elsif !is_int args[1]
972
+ return(cmd_fail(sock,"ACK [2@0] {swap} \"#{args[1]}\" is not a integer"))
973
+ elsif args[0].to_i >= @the_playlist.length or args[0].to_i < 0
974
+ return(cmd_fail(sock,"ACK [50@0] {swap} song doesn't exist: \"#{args[0]}\""))
975
+ elsif args[1].to_i >= @the_playlist.length or args[1].to_i < 0
976
+ return(cmd_fail(sock,"ACK [50@0] {swap} song doesn't exist: \"#{args[1]}\""))
977
+ else
978
+ tmp = @the_playlist[args[1].to_i]
979
+ @the_playlist[args[1].to_i] = @the_playlist[args[0].to_i]
980
+ @the_playlist[args[0].to_i] = tmp
981
+ @the_playlist[args[0].to_i]['_mod_ver'] = @status[:playlist]
982
+ @the_playlist[args[1].to_i]['_mod_ver'] = @status[:playlist]
983
+ incr_version
984
+ return true
985
+ end
986
+ end
987
+ when 'swapid'
988
+ args_check( sock, cmd, args, 2 ) do |args|
989
+ if !is_int args[0]
990
+ return(cmd_fail(sock,"ACK [2@0] {swapid} \"#{args[0]}\" is not a integer"))
991
+ elsif !is_int args[1]
992
+ return(cmd_fail(sock,"ACK [2@0] {swapid} \"#{args[1]}\" is not a integer"))
993
+ else
994
+ from = nil
995
+ to = nil
996
+ @the_playlist.each_with_index do |song,i|
997
+ if song['id'] == args[0].to_i
998
+ from = i
999
+ elsif song['id'] == args[1].to_i
1000
+ to = i
1001
+ end
1002
+ end
1003
+ if from.nil?
1004
+ return(cmd_fail(sock,"ACK [50@0] {swapid} song id doesn't exist: \"#{args[0]}\""))
1005
+ elsif to.nil?
1006
+ return(cmd_fail(sock,"ACK [50@0] {swapid} song id doesn't exist: \"#{args[1]}\""))
1007
+ end
1008
+ tmp = @the_playlist[to]
1009
+ @the_playlist[to] = @the_playlist[from]
1010
+ @the_playlist[from] = tmp
1011
+ @the_playlist[to]['_mod_ver'] = @status[:playlist]
1012
+ @the_playlist[from]['_mod_ver'] = @status[:playlist]
1013
+
1014
+ incr_version
1015
+ return true
1016
+ end
1017
+ end
1018
+ when 'update'
1019
+ args_check( sock, cmd, args, 0..1 ) do |args|
1020
+ incr_version
1021
+ sock.puts 'updating_db: 1'
1022
+ @status[:updating_db] = '1'
1023
+ return true
1024
+ end
1025
+ when 'volume'
1026
+ log 'MPD Warning: Call to Deprecated API: "volume"' if audit
1027
+ args_check( sock, cmd, args, 1 ) do |args|
1028
+ if !is_int args[0]
1029
+ return(cmd_fail(sock,'ACK [2@0] {volume} need an integer'))
1030
+ else
1031
+ # Note: args[0] < 0 subtract from the volume
1032
+ @status[:volume] += args[0].to_i
1033
+ return true
1034
+ end
1035
+ end
1036
+ else
1037
+ return(cmd_fail(sock,"ACK [5@0] {} unknown command #{cmd}"))
1038
+ end # End Case cmd
1039
+ end
1040
+
1041
+ def get_current_song
1042
+ if @current_song != nil and @current_song < @the_playlist.length
1043
+ return @the_playlist[@current_song]
1044
+ else
1045
+ return nil
1046
+ end
1047
+ end
1048
+
1049
+ def prev_song
1050
+ return if @current_song.nil?
1051
+ if @current_song == 0
1052
+ @elapsed_time = 0
1053
+ else
1054
+ @current_song -= 1
1055
+ end
1056
+ end
1057
+
1058
+ def next_song
1059
+ return if @current_song.nil?
1060
+ @current_song = (@current_song +1 < @the_playlist.length ? @current_song +1 : nil)
1061
+ end
1062
+
1063
+ def elapsed_time=( new_time )
1064
+ @elapsed_time = new_time
1065
+ end
1066
+
1067
+ def elapsed_time
1068
+ @elapsed_time
1069
+ end
1070
+
1071
+ def incr_version
1072
+ if @status[:playlist] == 2147483647
1073
+ @status[:playlist] = 1
1074
+ @the_playlist.each do |song|
1075
+ song['_mod_ver'] = 0
1076
+ end
1077
+ else
1078
+ @status[:playlist] += 1
1079
+ end
1080
+ end
1081
+
1082
+ def cmd_fail( sock, msg )
1083
+ sock.puts msg
1084
+ return false
1085
+ end
1086
+
1087
+ def build_args( line )
1088
+ ret = []
1089
+ word = ''
1090
+ escaped = false
1091
+ in_quote = false
1092
+
1093
+ line.strip!
1094
+
1095
+ line.each_byte do |c|
1096
+ c = c.chr
1097
+ if c == ' ' and !in_quote
1098
+ ret << word unless word.empty?
1099
+ word = ''
1100
+ elsif c == '"' and !escaped
1101
+ if in_quote
1102
+ in_quote = false
1103
+ else
1104
+ in_quote = true
1105
+ end
1106
+ ret << word unless word.empty?
1107
+ word = ''
1108
+ else
1109
+ escaped = (c == '\\')
1110
+ word += c
1111
+ end
1112
+ end
1113
+
1114
+ ret << word unless word.empty?
1115
+
1116
+ return ret
1117
+ end
1118
+
1119
+ def args_check( sock, cmd, argv, argc )
1120
+ if (argc.kind_of? Range and argc.include?(argv.length)) or
1121
+ (argv.length == argc)
1122
+ yield argv
1123
+ else
1124
+ sock.puts "ACK [2@0] {#{cmd}} wrong number of arguments for \"#{cmd}\""
1125
+ end
1126
+ end
1127
+
1128
+ def is_int( val )
1129
+ val =~ /^[-+]?[0-9]*$/
1130
+ end
1131
+
1132
+ def is_bool( val )
1133
+ val == '0' or val == '1'
1134
+ end
1135
+
1136
+ def locate_dir( path )
1137
+ dirs = path.split '/'
1138
+
1139
+ the_dir = @filetree
1140
+ dirs.each do |d|
1141
+ found = nil
1142
+ the_dir[:dirs].each do |sub|
1143
+ if sub[:name] == d
1144
+ found = sub
1145
+ break
1146
+ end
1147
+ end
1148
+ if found.nil?
1149
+ return nil
1150
+ else
1151
+ the_dir = found
1152
+ end
1153
+ end
1154
+
1155
+ return the_dir
1156
+ end
1157
+
1158
+ def send_song( sock, song )
1159
+ return if song.nil?
1160
+ sock.puts "file: #{song['file']}"
1161
+ song.each_pair do |key,val|
1162
+ sock.puts "#{key.capitalize}: #{val}" unless key == 'file' or key == '_mod_ver'
1163
+ end
1164
+ end
1165
+
1166
+ def send_dir( sock, dir, allinfo, path = '' )
1167
+ sock.puts "directory: #{path}#{dir[:name]}"
1168
+
1169
+ dir[:songs].each do |song|
1170
+ if allinfo
1171
+ send_song sock, song
1172
+ else
1173
+ sock.puts "file: #{song['file']}"
1174
+ end
1175
+ end
1176
+
1177
+ dir[:dirs].each do |d|
1178
+ send_dir(sock, d, allinfo, dir[:name] + '/')
1179
+ end
1180
+ end
1181
+
1182
+ def add_dir_to_pls( dir )
1183
+ dir[:songs].each do |song|
1184
+ song['_mod_ver'] = @status[:playlist]
1185
+ incr_version
1186
+ @the_playlist << song
1187
+ end
1188
+
1189
+ dir[:dirs].each do |d|
1190
+ add_dir_to_pls d
1191
+ end
1192
+ end
1193
+
1194
+ def sort_dir( dir )
1195
+ dir[:dirs].sort! do |x,y|
1196
+ x[:name] <=> y[:name]
1197
+ end
1198
+
1199
+ dir[:dirs].each do |d|
1200
+ sort_dir d
1201
+ end
1202
+ end
1203
+
1204
+ end