rwdmpd 0.06

Sign up to get free protection for your applications and to get access to all the features.
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