diff --git a/resources/lib/monitor.py b/resources/lib/monitor.py index ba9f15ad..2cef71da 100644 --- a/resources/lib/monitor.py +++ b/resources/lib/monitor.py @@ -18,6 +18,7 @@ from client import get_device_id from objects import Actions, PlaylistWorker, on_play, on_update, special_listener from helper import _, settings, window, dialog, event, api, JSONRPC from emby import Emby +from webservice import WebService ################################################################################################# @@ -37,6 +38,8 @@ class Monitor(xbmc.Monitor): self.device_id = get_device_id() self.listener = Listener(self) self.listener.start() + self.webservice = WebService() + self.webservice.start() xbmc.Monitor.__init__(self) def onScanStarted(self, library): diff --git a/resources/lib/webservice.py b/resources/lib/webservice.py new file mode 100644 index 00000000..83224ad8 --- /dev/null +++ b/resources/lib/webservice.py @@ -0,0 +1,179 @@ +# -*- coding: utf-8 -*- + +################################################################################################# + +import SimpleHTTPServer +import BaseHTTPServer +import logging +import httplib +import threading +import urlparse +import urllib + +import xbmc +import xbmcvfs + +################################################################################################# + +PORT = 57578 +LOG = logging.getLogger("EMBY."+__name__) + +################################################################################################# + + +class WebService(threading.Thread): + + ''' Run a webservice to trigger playback. + Inspired from script.skin.helper.service by marcelveldt. + ''' + stop_thread = False + + def __init__(self): + threading.Thread.__init__(self) + + def stop(self): + + ''' Called when the thread needs to stop + ''' + try: + conn = httplib.HTTPConnection("127.0.0.1:%d" % PORT) + conn.request("QUIT", "/") + conn.getresponse() + self.stop_thread = True + except Exception as error: + LOG.exception(error) + + def run(self): + + ''' Called to start the webservice. + ''' + LOG.info("--->[ webservice/%s ]", PORT) + + try: + server = StoppableHttpServer(('127.0.0.1', PORT), StoppableHttpRequestHandler) + server.serve_forever() + except Exception as error: + + if '10053' not in error: # ignore host diconnected errors + LOG.exception(error) + + LOG.info("---<[ webservice ]") + + +class Request(object): + + ''' Attributes from urlsplit that this class also sets + ''' + uri_attrs = ('scheme', 'netloc', 'path', 'query', 'fragment') + + def __init__(self, uri, headers, rfile=None): + + self.uri = uri + self.headers = headers + parsed = urlparse.urlsplit(uri) + + for i, attr in enumerate(self.uri_attrs): + setattr(self, attr, parsed[i]) + + try: + body_len = int(self.headers.get('Content-length', 0)) + except ValueError: + body_len = 0 + + self.body = rfile.read(body_len) if body_len and rfile else None + + +class StoppableHttpServer(BaseHTTPServer.HTTPServer): + + ''' Http server that reacts to self.stop flag. + ''' + def serve_forever(self): + + ''' Handle one request at a time until stopped. + ''' + self.stop = False + + while not self.stop: + + self.handle_request() + xbmc.sleep(100) + + +class StoppableHttpRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): + + ''' http request handler with QUIT stopping the server + ''' + raw_requestline = "" + + def __init__(self, request, client_address, server): + try: + SimpleHTTPServer.SimpleHTTPRequestHandler.__init__(self, request, client_address, server) + except Exception: + pass + + def do_QUIT(self): + + ''' send 200 OK response, and set server.stop to True + ''' + self.send_response(200) + self.end_headers() + self.server.stop = True + + def parse_request(self): + + ''' Modify here to workaround unencoded requests. + ''' + retval = SimpleHTTPServer.SimpleHTTPRequestHandler.parse_request(self) + self.request = Request(self.path, self.headers, self.rfile) + + return retval + + def do_HEAD(self): + + ''' Called on HEAD requests + ''' + self.handle_request(True) + + return + + def get_params(self): + + ''' Get the params + ''' + try: + params = dict(urlparse.parse_qsl(self.path[1:])) + except Exception: + params = {} + + return params + + def handle_request(self, headers_only=False): + + ''' Send headers and reponse + ''' + try: + params = self.get_params() + LOG.info("Webservice called with params: %s", params) + + path = ("plugin://plugin.video.emby?mode=play&id=%s&dbid=%s&filename=%s" + % (params.get('Id'), params.get('KodiId'), params.get('Name'))) + self.send_response(200) + self.send_header('Content-type', 'text/html') + self.send_header('Content-Length', len(path)) + self.end_headers() + self.wfile.write(path.encode('utf-8')) + + except Exception as error: + + LOG.exception(error) + self.send_error(500, 'Exception occurred: %s' % error) + + return + + def do_GET(self): + + ''' Called on GET requests + ''' + self.handle_request() + + return