You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
amarok/amarok/src/scripts/webcontrol/RequestHandler.py

267 lines
7.6 KiB

#!/usr/bin/env python
# -*- coding: Latin-1 -*-
"""
This scripts starts a small http-server that serves the current-playlist as
HTML. Start it and point your browser to http://localhost:4773/
Author: André Kelpe fs111 at web dot de
: Jonas Drewsen kde at xspect dot dk
License: GPL
"""
import SimpleHTTPServer
import BaseHTTPServer
from Playlist import Playlist
import Globals
import time
# necessary for <= python2.2 that cannot handle "infds" in var
import string
PLIST = None
# keep track of request ids in order to not repeat
# requests if user refreshes his browser
REQ_IDS = {}
#
# Holding current AmarokStatus. A bunch of init_XXX functions in
# order to begin dcop requests as early as possible to avoid too
# much latency
#
class AmarokStatus:
EngineEmpty = 1
EngineIdle = 2
EnginePause = 3
EnginePlay = 4
allowControl = 0
publish = 0
playState = -1
dcop_isplaying = None
dcop_volume = None
dcop_trackcurrentindex = None
dcop_trackcurrenttime = None
dcop_tracktotaltime = None
def __init__(self):
self.controls_enabled = 0
self.time_left = None
self.dcop_isplaying = Globals.PlayerDcop("isPlaying")
self.dcop_volume = Globals.PlayerDcop("getVolume")
self.dcop_trackcurrentindex = Globals.PlaylistDcop("getActiveIndex")
self.dcop_trackcurrenttime = Globals.PlayerDcop("trackCurrentTime")
self.dcop_tracktotaltime = Globals.PlayerDcop("trackTotalTime")
def isPlaying(self):
if self.playState != -1:
res = self.playState == self.EnginePlay
else:
res = string.find(self.dcop_isplaying.result(), "true") >= 0
if res:
self.playState = self.EnginePlay
else:
self.playState = self.EnginePause
return res
def getActiveIndex(self):
return int(self.dcop_trackcurrentindex.result())
def getVolume(self):
return int(self.dcop_volume.result())
def timeLeft(self):
cur = int(self.dcop_trackcurrenttime.result())
total = int(self.dcop_tracktotaltime.result())
return total - cur
def controlsEnabled(self):
return self.allowControl
class RequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
"""We need our own 'RequestHandler, to handle the requests, that arrive at
our server."""
def _amarokPlay(self):
AmarokStatus.playState = AmarokStatus.EnginePlay
Globals._dcopCallPlayer("play")
def _amarokPause(self):
AmarokStatus.playState = AmarokStatus.EnginePause
Globals._dcopCallPlayer("pause")
def _amarokNext(self):
Globals._dcopCallPlayer("next")
def _amarokGoto(self,index):
AmarokStatus.playState = AmarokStatus.EnginePlay
AmarokStatus.currentTrackIndex = int(index)
Globals._dcopCallPlaylistArg("playByIndex",index)
def _amarokPrev(self):
Globals._dcopCallPlayer("prev")
def _amarokStop(self):
Globals._dcopCallPlayer("stop")
AmarokStatus.playState = AmarokStatus.EngineStop
def _amarokSetVolume(self, val):
Globals._dcopCallPlayerArg("setVolume",val)
def _parseQueryVars(self):
querystr = self.path.split("?")
qmap = {}
if len(querystr) <= 1:
return qmap
queries = querystr[-1].split("&");
for query in queries:
var = query.split("=")
if len(var) != 2:
continue
qmap[var[0]] = var[1]
return qmap
def _handleAction(self, qmap):
global REQ_IDS
# get the sessions last reqid
try:
req_id = REQ_IDS[qmap["sesid"]]
except:
return 0
# abort a request that has already been completed
# probably a refresh from the users browser
if qmap.has_key("reqid") and req_id == int(qmap["reqid"]):
return 0
if qmap.has_key("action"):
a = qmap["action"]
if a == "stop":
self._amarokStop()
elif a == "play":
self._amarokPlay()
elif a == "pause":
self._amarokPause()
elif a == "prev":
self._amarokPrev()
elif a == "next":
self._amarokNext()
elif a == "goto":
self._amarokGoto(qmap["value"])
elif a == "setvolume":
self._amarokSetVolume(qmap["value"])
return 1
def _amarokStatus(self):
status = AmarokStatus()
return status
def _sendFile(self, path):
# only allow doc root dir access
elem = self.path.split("/")
if len(elem):
path = elem[-1]
f = open(Globals.EXEC_PATH + "/" + path, 'r')
self.copyfile(f, self.wfile)
def do_HEAD(self):
"""Serve a HEAD request."""
RequestHandler.extensions_map.update({
'': 'application/octet-stream', # Default
'.png': 'image/png',
'.js': 'text/plain',
'.css': 'text/plain'
})
f = self.send_head()
if f:
f.close()
def _getSessionInfo(self, qmap):
# get the sessions last reqid
last_req_id = 0
session_id = None
if qmap.has_key("sesid"):
session_id = qmap["sesid"]
if REQ_IDS.has_key(session_id):
last_req_id = REQ_IDS[session_id]
else:
REQ_IDS[session_id] = last_req_id
else:
# Create a session
session_id = str(time.time())
REQ_IDS[session_id] = last_req_id
return session_id, last_req_id
def do_GET(self):
"""Overwrite the do_GET-method of the super class."""
RequestHandler.extensions_map.update({
'': 'application/octet-stream', # Default
'.png': 'image/png',
'.js': 'text/plain',
'.css': 'text/plain'
})
global REQ_IDS
qmap = self._parseQueryVars()
session_id, last_req_id = self._getSessionInfo(qmap)
if AmarokStatus.allowControl and self._handleAction(qmap):
last_req_id = last_req_id + 1
REQ_IDS[session_id] = last_req_id
newreqid = last_req_id + 1
#
# Surely there must be a better way that this:)
#
self.send_response(200)
if string.find(self.path, ".png") >= 0:
self.send_header("content-type","image/png")
self.end_headers()
self._sendFile(self.path)
elif string.find(self.path, ".js") >= 0:
self.send_header("content-type","text/plain")
self.end_headers()
self._sendFile(self.path)
elif string.find(self.path, ".css") >= 0:
self.send_header("content-type","text/css")
self.end_headers()
self._sendFile(self.path)
else:
status = self._amarokStatus()
status.dcop_volume.init()
status.dcop_trackcurrenttime.init()
status.dcop_tracktotaltime.init()
self.send_header("content-type","text/html")
self.send_header("Cache-Control","no-cache")
self.end_headers()
status.reqid = newreqid
status.sesid = session_id
self.wfile.write(PLIST.toHtml(status))
def main():
"""main is the starting-point for our script."""
global PLIST
PLIST = Playlist()
srv = BaseHTTPServer.HTTPServer(('',Globals.PORT),RequestHandler)
srv.serve_forever()
if __name__ == "__main__":
main()