#!/usr/bin/env python #usage: simple-mpc-remote [options] #based on mplayer-remote v0.0.4, http://www.gwenn.dk/mplayer-remote.html import BaseHTTPServer, commands, sys, os, pwd, grp, socket from optparse import OptionParser parser = OptionParser(description='%prog - a simple mpc web control', usage='%prog [options]') parser.add_option("-p", "--port", dest="port", action="store", help='local port to bind (default 80).') (options, args) = parser.parse_args() if options.port: port = int(options.port) else: port = 80 if port < 1024: if not os.geteuid() == 0: sys.exit(os.path.basename(__file__) + ": root permitions are necessary to bind to port " + str(port) + ", use -p to specify a non privileged port or run as root.") # The following string variables contain the HTML code that we will # serve to the client # pagehead: Code that is common to all pages, including CSS code # pageend: Code that is common to all pages, closing the HTML page # pagectrl: Code for control widgets pagehead = """ Remote mpc
""" pagectrl = """

Mpd Control



Volume


""" pageend = """
""" ctrlcmd = { "%7C%3C" :"prev", # |< "%3C%3C" :"seek -20%", # << "%3C" :"seek -5%", # < "%3E%7C%7C" :"toggle", # >|| "%3E" :"seek +5%", # > "%3E%3E" :"seek +20%", # >> "%3E%7C" :"next", # >| "quit" :"stop", # quit "fullscreen":"vo_fullscreen" # fullscreen } volcmd = {"%2B" :"amixer --quiet set Master 1%+", #+ "-" :"amixer --quiet set Master 1%-", #- "mute":"amixer --quiet set Master toggle"} #mute def drop_privileges(): if os.getuid() != 0: #we're not root so, whatever dude return #get the uid/gid from the name user_name = os.getenv("SUDO_USER") pwnam = pwd.getpwnam(user_name) #remove group privileges os.setgroups([]) #try setting the new uid/gid os.setgid(pwnam.pw_gid) os.setuid(pwnam.pw_uid) #ensure a reasonable umask old_umask = os.umask(0o22) print "Dropping user privileges: root -> " + user_name def execute(cmd): """ Execute a shell command, while handling errors gracefully""" (stat, out) = commands.getstatusoutput(cmd) if stat != 0: print >>sys.stderr, "ERROR: '"+cmd+"' returned "+ str(out) return out class myHandler(BaseHTTPServer.BaseHTTPRequestHandler): """Handles all http requests.""" def __init__(self, *args): """Initialise the handler (called each time we handle a request)""" BaseHTTPServer.BaseHTTPRequestHandler.__init__(self, *args) def write(self, x): """Send some html code to the browser""" return self.wfile.write(x) def handleCmd(self,param): """Global handler of commands, doesn't care what the page is, just executes the correct commands if possible""" if "mpc" in param: if param["mpc"] in ctrlcmd: self.write(execute("mpc " + ctrlcmd[param["mpc"]])) print "exec: mpc " + ctrlcmd[param["mpc"]] if "volume" in param: if param["volume"] in volcmd: self.write(execute(volcmd[param["volume"]])) print "exec: " + volcmd[param["volume"]] def volumebar(self): """Get the current volume setting and plot it as a "bar diagram", or if muted, indicate this""" out = execute("amixer get Master").split() vol = execute("amixer get 'Master',0|egrep -m1 -o '[0-9]{1,3}%'") if vol != "0%": self.write('
'+vol+'
') else: self.write('
Muted
') def do_GET(self): """Handle the GET request. This identifies the page that is being served, and handles the submitted form variables""" self.send_response(200) self.send_header('Content-type','text/html') self.end_headers() self.write(pagehead) file = self.path.split('/')[-1] paramstr=file.split('?') print "args:", paramstr param = {} if len(paramstr) > 1: for p in paramstr[1].split('&'): s = p.split('=') param[s[0]] = s[1] self.handleCmd(param) #self.volumebar() self.write(pagectrl) self.write(pageend) class StoppableHTTPServer(BaseHTTPServer.HTTPServer): """ This is a simple change to the normal basehttp server which is not blocked waiting for HTTP connections """ def server_bind(self): BaseHTTPServer.HTTPServer.server_bind(self) self.socket.settimeout(1) self.run = True def get_request(self): while self.run: try: sock, addr = self.socket.accept() sock.settimeout(None) return (sock, addr) except socket.timeout: pass def run(): """ This is the "main" function, that gets called from the end of the file, after everything has been parsed. """ try: server = StoppableHTTPServer(('', port), myHandler) print 'Started httpserver on port ' , port drop_privileges() server.serve_forever() except KeyboardInterrupt: print '^C received, shutting down the web server' finally: if 'server' in locals(): server.socket.close() # Finally, just execute it all run()