#!/usr/bin/ruby -w # Simple web interface to music player daemon in Ruby. # More information on mpd can be found at http://www.musicpd.org/ # require 'librmpd' # librmpd is incomprehensibly bad. playlistinfo takes 30 damned seconds and isn't actually fucking named playlistinfo. require 'mpd' # Whereas here, playlistinfo takes one second and is fucking named playlistinfo. $VERBOSE = nil # mpd.rb is a bit noisy about versions, though. require 'cgi' cgi = CGI.new m = MPD.new def output_info(m) currentsong = m.currentsong status = m.status stats = m.stats playlistinfo = m.playlistinfo position = currentsong['pos'].to_i times = status['time'].split(':') listeners = 0 File.open('/proc/net/tcp', 'r').each do |line| # if local port 8000 #if /^.{6}[0-9A-F]{8}:1F40 (?!00000000:0000)/ =~ line #255.255.255.255:4369 not LISTENing # if remote port 8000 (i.e. proxy) if /^.{20}[0-9A-F]{8}:1F40/ =~ line listeners += 1 end end print 'Content-type: text/html; charset=utf-8 Pragma: no-cache Cache-Control: private, max-age=0, no-cache Refresh: 30; URL=', ENV['REQUEST_URI'].sub(/\?.+/,''), '
Playing ' format_songinfo(currentsong) print ' for ', listeners, ' listeners.
This song is ', times[0].to_i*100/times[1].to_i, '% complete (', times[0], ' of ', times[1], ' seconds played).
This is song ', position+1, ' of ', status['playlistlength'], ' total in the library. Next!
', stats['playtime'].to_i/864/100.0, ' days into playlist length of ', stats['db_playtime'].to_i/864/100.0, ' days.
Here are the proximal songs:
'
# In principle, the POST method is more semantically correct, but GET with Cache-Control: no-cache makes linking easier
#
min = 0
max = position+10
( position >= 10 ) && ( min = position-10 )
( max > status['playlistlength'].to_i ) && ( max = status['playlistlength'].to_i )
playlistinfo[min..max].each do |songinfo|
( songinfo['pos'] == position ) && ( print '' )
print 'Queue ' , songinfo['pos'], ' '
format_songinfo(songinfo)
( songinfo['pos'] == position ) && ( print '' )
puts
end
print '
'
end
def output_stopped()
print 'Content-type: text/html; charset=utf-8
MPD is stopped.
' end def output_playlist(m) print 'Content-type: text/html; charset=utf-8Return to main
Load pre-existing playlist: ' m.lsplaylists.each do |playlist| print '', playlist, ' '; end print '
'
m.playlistinfo.each do |songinfo| # One giant object
print '', songinfo['pos'], ' '
format_songinfo(songinfo)
print '
'
end
print'
'
end
def format_songinfo(songinfo)
if songinfo['artist'] && songinfo['title']
print CGI.escapeHTML( songinfo['artist'] + ' - ' + songinfo['title'] )
elsif songinfo['title']
print CGI.escapeHTML( songinfo['title'] )
else
print CGI.escapeHTML( songinfo['file'] )
end
end
def queue(m,songpos)
curpos = m.currentsong['pos'].to_i
if songpos <= curpos # mpd is a little screwy about how it handles playlist reordering
m.move(songpos, curpos)
elsif songpos > curpos
m.move(songpos, curpos+1)
end
end
if cgi.params['ajaxqueue'][0] =~ /^\d+$/ # ?ajaxqueue=55385
songinfo = m.playlistid(cgi.params['ajaxqueue'][0])
queue(m, songinfo['pos'].to_i)
print 'Content-type: application/xhtml+xml; charset=utf-8
'
format_songinfo(songinfo)
print ' has been requeued.'
elsif cgi.params['queue'][0] =~ /^\d+$/ # ?queue=55385
queue(m, m.playlistid(cgi.params['queue'][0])['pos'].to_i)
output_info(m)
elsif cgi.params['playlist'][0] =~ /.+/ # ?playlist=something
m.crop
m.load(cgi.params['playlist'][0])
m.shuffle
output_info(m)
elsif cgi.params.has_key? 'playlist' # ?playlist
output_playlist(m)
elsif m.status['state'] == 'play' # mpd playing?
if cgi.params.has_key? 'change' # ?change
m.next
end
output_info(m)
else # mpd not playing
if cgi.params.has_key? 'start'# ?start
m.play
output_info(m)
else # stopped display
output_stopped()
end
end