def do_cmd( sock, cmd, args )
case cmd
when 'add'
if args.length == 0
@songs.each do |s|
s['_mod_ver'] = @status[:playlist]
incr_version
@the_playlist << s
end
return true
else
the_song = nil
@songs.each do |s|
if s['file'] == args[0]
the_song = s
break
end
end
if the_song.nil?
dir = locate_dir(args[0])
if not dir.nil?
add_dir_to_pls dir
return true
else
return(cmd_fail(sock,'ACK [50@0] {add} directory or file not found'))
end
else
the_song['_mod_ver'] = @status[:playlist]
incr_version
@the_playlist << the_song
return true
end
end
when 'clear'
args_check( sock, cmd, args, 0 ) do
incr_version
@the_playlist = []
@current_song = nil
return true
end
when 'clearerror'
args_check( sock, cmd, args, 0 ) do
the_error = nil
return true
end
when 'close'
sock.close
return true
when 'crossfade'
args_check( sock, cmd, args, 1 ) do |args|
if is_int(args[0]) and args[0].to_i >= 0
@status[:xfade] = args[0].to_i
return true
else
return(cmd_fail(sock,"ACK [2@0] {crossfade} \"#{args[0]}\" is not a integer >= 0"))
end
end
when 'currentsong'
args_check( sock, cmd, args, 0 ) do
if @current_song != nil and @current_song < @the_playlist.length
send_song sock, @the_playlist[@current_song]
end
return true
end
when 'delete'
args_check( sock, cmd, args, 1 ) do |args|
if is_int args[0]
if args[0].to_i < 0 or args[0].to_i >= @the_playlist.length
return(cmd_fail(sock,"ACK [50@0] {delete} song doesn't exist: \"#{args[0]}\""))
else
@the_playlist.delete_at args[0].to_i
args[0].to_i.upto @the_playlist.length - 1 do |i|
@the_playlist[i]['_mod_ver'] = @status[:playlist]
end
incr_version
return true
end
else
return(cmd_fail('ACK [2@0] {delete} need a positive integer'))
end
end
when 'deleteid'
args_check( sock, cmd, args, 1 ) do |args|
if is_int args[0]
the_song = nil
@the_playlist.each do |song|
if song['id'] == args[0].to_i
the_song = song
break
end
end
if not the_song.nil?
index = @the_playlist.index the_song
@the_playlist.delete the_song
index.upto @the_playlist.length - 1 do |i|
@the_playlist[i]['_mod_ver'] = @status[:playlist]
end
incr_version
return true
else
return(cmd_fail(sock,"ACK [50@0] {deleteid} song id doesn't exist: \"#{args[0]}\""))
end
else
return(cmd_fail(sock,'ACK [2@0] {deleteid} need a positive integer'))
end
end
when 'find'
args_check( sock, cmd, args, 2 ) do |args|
if args[0] != 'album' and args[0] != 'artist' and args[0] != 'title'
return(cmd_fail(sock,'ACK [2@0] {find} incorrect arguments'))
else
if args[0] == 'album'
@songs.each do |song|
if song['album'] == args[1]
send_song sock, song
end
end
elsif args[0] == 'artist'
@songs.each do |song|
if song['artist'] == args[1]
send_song sock, song
end
end
elsif args[0] == 'title'
@songs.each do |song|
if song['title'] == args[1]
send_song sock, song
end
end
end
return true
end
end
when 'kill'
args_check( sock, cmd, args, 0 ) do
sock.close
return true
end
when 'list'
args_check( sock, cmd, args, 1..2 ) do |args|
if args[0] != 'album' and args[0] != 'artist' and args[0] != 'title'
return(cmd_fail(sock,"ACK [2@0] {list} \"#{args[0]}\" is not known"))
elsif args[0] == 'artist' and args.length > 1
return(cmd_fail(sock,'ACK [2@0] {list} should be "Album" for 3 arguments'))
else
if args[0] == 'artist'
@artists.each do |artist|
sock.puts "Artist: #{artist}"
end
return true
elsif args[0] == 'title'
@titles.each do |title|
sock.puts "Title: #{title}"
end
return true
else
if args.length == 2
listed = []
@songs.each do |song|
if song['artist'] == args[1]
if not song['album'].nil? and !listed.include? song['album']
sock.puts "Album: #{song['album']}"
listed << song['album']
end
end
end
return true
else
@albums.each do |album|
sock.puts "Album: #{album}"
end
return true
end
end
end
end
when 'listall'
args_check( sock, cmd, args, 0..1 ) do |args|
if args.length == 0
@filetree[:dirs].each do |d|
send_dir sock, d, false
end
else
was_song = false
@songs.each do |song|
if song['file'] == args[0]
sock.puts "file: #{song['file']}"
was_song = true
break
end
end
if was_song
return true
end
dir = locate_dir args[0]
if not dir.nil?
parents = args[0].split '/'
parents.pop
parents = parents.join '/'
parents += '/' unless parents.length == 0
send_dir sock, dir, false, parents
else
return(cmd_fail(sock,'ACK [50@0] {listall} directory or file not found'))
end
end
return true
end
when 'listallinfo'
args_check( sock, cmd, args, 0..1 ) do |args|
if args.length == 0
@filetree[:dirs].each do |d|
send_dir sock, d, true
end
else
was_song = false
@songs.each do |song|
if song['file'] == args[0]
send_song song
was_song = true
break
end
end
if was_song
return true
end
dir = locate_dir args[0]
if not dir.nil?
parents = args[0].split '/'
parents.pop
parents = parents.join '/'
parents += '/' unless parents.length == 0
send_dir sock, dir, true, parents
else
return(cmd_fail(sock,'ACK [50@0] {listallinfo} directory or file not found'))
end
end
return true
end
when 'load'
args_check( sock, cmd, args, 1 ) do
pls = args[0] + '.m3u'
the_pls = nil
@playlists.each do |p|
if p['file'] == pls
the_pls = p
break
end
end
unless the_pls.nil?
the_pls['songs'].each do |song|
song['_mod_ver'] = @status[:playlist]
@the_playlist << song
incr_version
end
else
return(cmd_fail(sock,"ACK [50@0] {load} playlist \"#{args[0]}\" not found"))
end
end
when 'lsinfo'
args_check( sock, cmd, args, 0..1 ) do
if args.length == 0
@filetree[:dirs].each do |d|
sock.puts "directory: #{d[:name]}"
d[:songs].each do |s|
send_song sock, s
end
end
@playlists.each do |pls|
sock.puts "playlist: #{pls['file'].gsub( /\.m3u$/, '' )}"
end
else
dir = locate_dir args[0]
if dir.nil?
return(cmd_fail(sock,"ACK [50@0] {lsinfo} directory not found"))
else
dir[:dirs].each do |d|
sock.puts "directory: #{args[0] + '/' + d[:name]}"
end
dir[:songs].each do |s|
send_song sock, s
end
end
end
return true
end
when 'move'
args_check( sock, cmd, args, 2 ) do |args|
if !is_int args[0]
return(cmd_fail(sock,"ACK [2@0] {move} \"#{args[0]}\" is not a integer"))
elsif !is_int args[1]
return(cmd_fail(sock,"ACK [2@0] {move} \"#{args[1]}\" is not a integer"))
elsif args[0].to_i < 0 or args[0].to_i >= @the_playlist.length
return(cmd_fail(sock,"ACK [50@0] {move} song doesn't exist: \"#{args[0]}\""))
elsif args[1].to_i < 0 or args[1].to_i >= @the_playlist.length
return(cmd_fail(sock,"ACK [50@0] {move} song doesn't exist: \"#{args[1]}\""))
else
tmp = @the_playlist.delete_at args[0].to_i
@the_playlist.insert args[1].to_i, tmp
if args[0].to_i < args[1].to_i
args[0].to_i.upto args[1].to_i do |i|
@the_playlist[i]['_mod_ver'] = @status[:playlist]
end
else
args[1].to_i.upto args[0].to_i do |i|
@the_playlist[i]['_mod_ver'] = @status[:playlist]
end
end
incr_version
return true
end
end
when 'moveid'
args_check( sock, cmd, args, 2 ) do |args|
if !is_int args[0]
return(cmd_fail(sock,"ACK [2@0] {moveid} \"#{args[0]}\" is not a integer"))
elsif !is_int args[1]
return(cmd_fail(sock,"ACK [2@0] {moveid} \"#{args[1]}\" is not a integer"))
elsif args[1].to_i < 0 or args[1].to_i >= @the_playlist.length
return(cmd_fail(sock,"ACK [50@0] {moveid} song doesn't exist: \"#{args[1]}\""))
else
the_song = nil
index = -1
@the_playlist.each_with_index do |song,i|
if song['id'] == args[0].to_i
the_song = song
index = i
end
end
if the_song.nil?
return(cmd_fail(sock,"ACK [50@0] {moveid} song id doesn't exist: \"#{args[0]}\""))
end
tmp = @the_playlist.delete_at index
@the_playlist.insert args[1].to_i, tmp
if index < args[1].to_i
index.upto args[1].to_i do |i|
@the_playlist[i]['_mod_ver'] = @status[:playlist]
end
else
args[1].to_i.upto index do |i|
@the_playlist[i]['_mod_ver'] = @status[:playlist]
end
end
incr_version
return true
end
end
when 'next'
args_check( sock, cmd, args, 0 ) do
if @status[:state] != 'stop'
next_song
@elapsed_time = 0
@status[:state] = 'play'
end
return true
end
when 'pause'
args_check( sock, cmd, args, 0..1 ) do |args|
if args.length > 0 and not is_bool args[0]
return(cmd_fail(sock,"ACK [2@0] {pause} \"#{args[0]}\" is not 0 or 1"))
end
if @status[:state] != 'stop'
if args.length == 1
@status[:state] = ( args[0] == '1' ? 'pause' : 'play' )
else
@status[:state] = ( @status[:state] == 'pause' ? 'play' : 'pause' )
end
end
return true
end
when 'password'
args_check( sock, cmd, args, 1 ) do |args|
return true if args[0] == 'test'
return(cmd_fail(sock,"ACK [3@0] {password} incorrect password"))
end
when 'ping'
args_check( sock, cmd, args, 0 ) do
return true
end
when 'play'
args_check( sock, cmd, args, 0..1 ) do |args|
if args.length > 0 and !is_int(args[0])
return(cmd_fail(sock,'ACK [2@0] {play} need a positive integer'))
else
args.clear if args[0] == '-1'
if args.length == 0
if @the_playlist.length > 0 and @status[:state] != 'play'
@current_song = 0 if @current_song.nil?
@elapsed_time = 0
@status[:state] = 'play'
end
else
if args[0].to_i < 0 or args[0].to_i >= @the_playlist.length
return(cmd_fail(sock,"ACK [50@0] {play} song doesn't exist: \"#{args[0]}\""))
end
@current_song = args[0].to_i
@elapsed_time = 0
@status[:state] = 'play'
end
return true
end
end
when 'playid'
args_check( sock, cmd, args, 0..1 ) do |args|
if args.length > 0 and !is_int(args[0])
return(cmd_fail(sock,'ACK [2@0] {playid} need a positive integer'))
else
args.clear if args[0] == '-1'
if args.length == 0
if @the_playlist.length > 0 and @status[:state] != 'play'
@current_song = 0 if @current_song.nil?
@elapsed_time = 0
@status[:state] = 'play'
end
else
index = nil
@the_playlist.each_with_index do |s,i|
if s['id'] == args[0].to_i
index = i
break;
end
end
return(cmd_fail(sock,"ACK [50@0] {playid} song id doesn't exist: \"#{args[0]}\"")) if index.nil?
@current_song = index
@elapsed_time = 0
@status[:state] = 'play'
end
return true
end
end
when 'playlist'
log 'MPD Warning: Call to Deprecated API: "playlist"' if audit
args_check( sock, cmd, args, 0 ) do
@the_playlist.each_with_index do |v,i|
sock.puts "#{i}:#{v['file']}"
end
return true
end
when 'playlistinfo'
args_check( sock, cmd, args, 0..1 ) do |args|
if args.length > 0 and !is_int(args[0])
return(cmd_fail(sock,'ACK [2@0] {playlistinfo} need a positive integer'))
else
args.clear if args.length > 0 and args[0].to_i < 0
if args.length != 0
if args[0].to_i >= @the_playlist.length
return(cmd_fail(sock,"ACK [50@0] {playlistinfo} song doesn't exist: \"#{args[0]}\""))
else
song = @the_playlist[args[0].to_i]
send_song sock, song
sock.puts "Pos: #{args[0].to_i}"
return true
end
else
@the_playlist.each_with_index do |song,i|
send_song sock, song
sock.puts "Pos: #{i}"
end
return true
end
end
end
when 'playlistid'
args_check( sock, cmd, args, 0..1 ) do |args|
if args.length > 0 and !is_int(args[0])
return(cmd_fail(sock,'ACK [2@0] {playlistid} need a positive integer'))
else
song = nil
pos = nil
args.clear if args[0].to_i < 0
if args.length != 0
@the_playlist.each_with_index do |s,i|
if s['id'] == args[0].to_i
song = s
pos = i
break;
end
end
return(cmd_fail(sock,"ACK [50@0] {playlistid} song id doesn't exist: \"#{args[0]}\"")) if song.nil?
send_song sock, song
sock.puts "Pos: #{pos}"
return true
else
@the_playlist.each_with_index do |song,i|
send_song sock, song
sock.puts "Pos: #{i}"
end
return true
end
end
end
when 'plchanges'
args_check( sock, cmd, args, 1 ) do |args|
if args.length > 0 and !is_int(args[0])
return(cmd_fail(sock,'ACK [2@0] {plchanges} need a positive integer'))
else
@the_playlist.each_with_index do |song,i|
if args[0].to_i > @status[:playlist] or song['_mod_ver'] >= args[0].to_i or song['_mod_ver'] == 0
send_song sock, song
sock.puts "Pos: #{i}"
end
end
return true
end
end
when 'plchangesposid'
args_check( sock, cmd, args, 1 ) do |args|
if args.length > 0 and !is_int(args[0])
return(cmd_fail(sock,'ACK [2@0] {plchangesposid} need a positive integer'))
else
@the_playlist.each_with_index do |song,i|
if args[0].to_i > @status[:playlist] or song['_mod_ver'] >= args[0].to_i or song['_mod_ver'] == 0
sock.puts "cpos: #{i}"
sock.puts "Id: #{song['id']}"
end
end
return true
end
end
when 'previous'
args_check( sock, cmd, args, 0 ) do
return true if @status[:state] == 'stop'
prev_song
@elapsed_time = 0
@status[:state] = 'play'
return true
end
when 'random'
args_check( sock, cmd, args, 1 ) do |args|
if is_bool args[0]
@status[:random] = args[0].to_i
return true
elsif is_int args[0]
return(cmd_fail(sock,"ACK [2@0] {random} \"#{args[0]}\" is not 0 or 1"))
else
return(cmd_fail(sock,'ACK [2@0] {random} need an integer'))
end
end
when 'repeat'
args_check( sock, cmd, args, 1 ) do |args|
if is_bool args[0]
@status[:repeat] = args[0].to_i
return true
elsif is_int args[0]
return(cmd_fail(sock,"ACK [2@0] {repeat} \"#{args[0]}\" is not 0 or 1"))
else
return(cmd_fail(sock,'ACK [2@0] {repeat} need an integer'))
end
end
when 'rm'
args_check( sock, cmd, args, 1 ) do |args|
rm_pls = args[0] + '.m3u'
the_pls = -1
@playlists.each_with_index do |pls,i|
the_pls = i if pls['file'] == rm_pls
end
if the_pls != -1
@playlists.delete_at the_pls
return true
else
return(cmd_fail(sock,"ACK [50@0] {rm} playlist \"#{args[0]}\" not found"))
end
end
when 'save'
args_check( sock, cmd, args, 1 ) do |args|
new_playlist = {'file' => args[0]+'.m3u', 'songs' => @the_playlist}
@playlists << new_playlist
return true
end
when 'search'
args_check( sock, cmd, args, 2 ) do |args|
if args[0] != 'title' and args[0] != 'artist' and args[0] != 'album' and args[0] != 'filename'
return(cmd_fail(sock,'ACK [2@0] {search} incorrect arguments'))
end
args[0] = 'file' if args[0] == 'filename'
@songs.each do |song|
data = song[args[0]]
if not data.nil? and data.downcase.include? args[1]
send_song sock, song
end
end
return true
end
when 'seek'
args_check( sock, cmd, args, 2 ) do |args|
if !is_int args[0]
return(cmd_fail(sock,"ACK [2@0] {seek} \"#{args[0]}\" is not a integer"))
elsif !is_int args[1]
return(cmd_fail(sock,"ACK [2@0] {seek} \"#{args[1]}\" is not a integer"))
else
if args[0].to_i > @the_playlist.length or args[0].to_i < 0
return(cmd_fail(sock,"ACK [50@0] {seek} song doesn't exist: \"#{args[0]}\""))
end
args[1] = '0' if args[1].to_i < 0
song = @the_playlist[args[0].to_i]
if args[1].to_i >= song['time'].to_i
if args[0].to_i + 1 < @the_playlist.length
@current_song = args[0].to_i + 1
@elapsed_time = 0
@status[:state] = 'play' unless @status[:state] == 'pause'
else
@current_song = nil
@elapsed_time = 0
@status[:state] = 'stop'
end
else
@current_song = args[0].to_i
@elapsed_time = args[1].to_i
@status[:state] = 'play' unless @status[:state] == 'pause'
end
return true
end
end
when 'seekid'
args_check( sock, cmd, args, 2 ) do |args|
if !is_int args[0]
return(cmd_fail(sock,"ACK [2@0] {seekid} \"#{args[0]}\" is not a integer"))
elsif !is_int args[1]
return(cmd_fail(sock,"ACK [2@0] {seekid} \"#{args[1]}\" is not a integer"))
else
pos = nil
song = nil
@the_playlist.each_with_index do |s,i|
if s['id'] == args[0].to_i
song = s
pos = i
break;
end
end
if song.nil?
return(cmd_fail(sock,"ACK [50@0] {seekid} song id doesn't exist: \"#{args[0]}\""))
end
args[1] = '0' if args[1].to_i < 0
if args[1].to_i >= song['time'].to_i
if pos + 1 < @the_playlist.length
@current_song = pos + 1
@elapsed_time = 0
@status[:state] = 'play' unless @status[:state] == 'pause'
else
@current_song = nil
@elapsed_time = 0
@status[:state] = 'stop'
end
else
@current_song = pos
@elapsed_time = args[1].to_i
@status[:state] = 'play' unless @status[:state] == 'pause'
end
return true
end
end
when 'setvol'
args_check( sock, cmd, args, 1 ) do |args|
if !is_int args[0]
return(cmd_fail(sock,'ACK [2@0] {setvol} need an integer'))
else
@status[:volume] = args[0].to_i
return true
end
end
when 'shuffle'
args_check( sock, cmd, args, 0 ) do
@the_playlist.each do |s|
s['_mod_ver'] = @status[:playlist]
end
incr_version
@the_playlist.reverse!
return true
end
when 'stats'
args_check( sock, cmd, args, 0 ) do
sock.puts "artists: #{@artists.size}"
sock.puts "albums: #{@albums.size}"
sock.puts "songs: #{@songs.size}"
sock.puts "uptime: 500"
time = 0
@songs.each do |s|
time += s['time'].to_i
end
sock.puts "db_playtime: #{time}"
sock.puts "db_update: 1159418502"
sock.puts "playtime: 10"
return true
end
when 'status'
args_check( sock, cmd, args, 0 ) do
@status.each_pair do |key,val|
sock.puts "#{key}: #{val}" unless val.nil?
end
sock.puts "playlistlength: #{@the_playlist.length}"
if @current_song != nil and @the_playlist.length > @current_song
sock.puts "song: #{@current_song}"
sock.puts "songid: #{@the_playlist[@current_song]['id']}"
end
@status[:updating_db] = nil
return true
end
when 'stop'
args_check( sock, cmd, args, 0 ) do
@status[:state] = 'stop'
@status[:time] = nil
@status[:bitrate] = nil
@status[:audio] = nil
return true
end
when 'swap'
args_check( sock, cmd, args, 2 ) do |args|
if !is_int args[0]
return(cmd_fail(sock,"ACK [2@0] {swap} \"#{args[0]}\" is not a integer"))
elsif !is_int args[1]
return(cmd_fail(sock,"ACK [2@0] {swap} \"#{args[1]}\" is not a integer"))
elsif args[0].to_i >= @the_playlist.length or args[0].to_i < 0
return(cmd_fail(sock,"ACK [50@0] {swap} song doesn't exist: \"#{args[0]}\""))
elsif args[1].to_i >= @the_playlist.length or args[1].to_i < 0
return(cmd_fail(sock,"ACK [50@0] {swap} song doesn't exist: \"#{args[1]}\""))
else
tmp = @the_playlist[args[1].to_i]
@the_playlist[args[1].to_i] = @the_playlist[args[0].to_i]
@the_playlist[args[0].to_i] = tmp
@the_playlist[args[0].to_i]['_mod_ver'] = @status[:playlist]
@the_playlist[args[1].to_i]['_mod_ver'] = @status[:playlist]
incr_version
return true
end
end
when 'swapid'
args_check( sock, cmd, args, 2 ) do |args|
if !is_int args[0]
return(cmd_fail(sock,"ACK [2@0] {swapid} \"#{args[0]}\" is not a integer"))
elsif !is_int args[1]
return(cmd_fail(sock,"ACK [2@0] {swapid} \"#{args[1]}\" is not a integer"))
else
from = nil
to = nil
@the_playlist.each_with_index do |song,i|
if song['id'] == args[0].to_i
from = i
elsif song['id'] == args[1].to_i
to = i
end
end
if from.nil?
return(cmd_fail(sock,"ACK [50@0] {swapid} song id doesn't exist: \"#{args[0]}\""))
elsif to.nil?
return(cmd_fail(sock,"ACK [50@0] {swapid} song id doesn't exist: \"#{args[1]}\""))
end
tmp = @the_playlist[to]
@the_playlist[to] = @the_playlist[from]
@the_playlist[from] = tmp
@the_playlist[to]['_mod_ver'] = @status[:playlist]
@the_playlist[from]['_mod_ver'] = @status[:playlist]
incr_version
return true
end
end
when 'update'
args_check( sock, cmd, args, 0..1 ) do |args|
incr_version
sock.puts 'updating_db: 1'
@status[:updating_db] = '1'
return true
end
when 'volume'
log 'MPD Warning: Call to Deprecated API: "volume"' if audit
args_check( sock, cmd, args, 1 ) do |args|
if !is_int args[0]
return(cmd_fail(sock,'ACK [2@0] {volume} need an integer'))
else
@status[:volume] += args[0].to_i
return true
end
end
else
return(cmd_fail(sock,"ACK [5@0] {} unknown command #{cmd}"))
end
end