mirror of
https://github.com/jellyfin/jellyfin-kodi.git
synced 2025-05-09 02:45:07 +00:00
Update webservice with cherrypy
Fix playback issues that was causing Kodi to hang up
This commit is contained in:
parent
b2bc90cb06
commit
158a736360
164 changed files with 42855 additions and 174 deletions
|
@ -2,17 +2,14 @@
|
|||
|
||||
#################################################################################################
|
||||
|
||||
import SimpleHTTPServer
|
||||
import BaseHTTPServer
|
||||
import logging
|
||||
import httplib
|
||||
import threading
|
||||
import urlparse
|
||||
import urllib
|
||||
|
||||
import xbmc
|
||||
import xbmcvfs
|
||||
|
||||
import cherrypy
|
||||
|
||||
#################################################################################################
|
||||
|
||||
PORT = 57578
|
||||
|
@ -21,181 +18,59 @@ LOG = logging.getLogger("EMBY."+__name__)
|
|||
#################################################################################################
|
||||
|
||||
|
||||
class Root(object):
|
||||
|
||||
@cherrypy.expose
|
||||
def default(self, *args, **kwargs):
|
||||
|
||||
try:
|
||||
if not kwargs.get('Id').isdigit():
|
||||
raise IndexError("Incorrect Id format: %s" % kwargs.get('Id'))
|
||||
|
||||
LOG.info("Webservice called with params: %s", kwargs)
|
||||
|
||||
return ("plugin://plugin.video.emby?mode=play&id=%s&dbid=%s&filename=%s&transcode=%s"
|
||||
% (kwargs.get('Id'), kwargs.get('KodiId'), kwargs.get('Name'), kwargs.get('transcode') or False))
|
||||
|
||||
except IndexError as error:
|
||||
LOG.error(error)
|
||||
|
||||
raise cherrypy.HTTPError(404, error)
|
||||
|
||||
except Exception as error:
|
||||
LOG.exception(error)
|
||||
|
||||
raise cherrypy.HTTPError(500, "Exception occurred: %s" % error)
|
||||
|
||||
class WebService(threading.Thread):
|
||||
|
||||
''' Run a webservice to trigger playback.
|
||||
Inspired from script.skin.helper.service by marcelveldt.
|
||||
'''
|
||||
stop_thread = False
|
||||
root = None
|
||||
|
||||
def __init__(self):
|
||||
|
||||
self.root = Root()
|
||||
cherrypy.config.update({
|
||||
'engine.autoreload.on' : False,
|
||||
'log.screen': False,
|
||||
'engine.timeout_monitor.frequency': 5,
|
||||
'server.shutdown_timeout': 1,
|
||||
})
|
||||
threading.Thread.__init__(self)
|
||||
|
||||
def run(self):
|
||||
|
||||
LOG.info("--->[ webservice/%s ]", PORT)
|
||||
conf = {
|
||||
'global': {
|
||||
'server.socket_host': '0.0.0.0',
|
||||
'server.socket_port': PORT
|
||||
}, '/': {}
|
||||
}
|
||||
cherrypy.quickstart(self.root, '/', conf)
|
||||
|
||||
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)
|
||||
cherrypy.engine.exit()
|
||||
self.join(0)
|
||||
|
||||
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 log_message(self, format, *args):
|
||||
|
||||
''' Mute the webservice requests.
|
||||
'''
|
||||
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:
|
||||
path = self.path[1:]
|
||||
|
||||
if '?' in path:
|
||||
path = path.split('?', 1)[1]
|
||||
|
||||
params = dict(urlparse.parse_qsl(path))
|
||||
except Exception:
|
||||
params = {}
|
||||
|
||||
return params
|
||||
|
||||
def handle_request(self, headers_only=False):
|
||||
|
||||
''' Send headers and reponse
|
||||
'''
|
||||
try:
|
||||
params = self.get_params()
|
||||
|
||||
if not params.get('Id').isdigit():
|
||||
raise IndexError("Incorrect Id format: %s" % params.get('Id'))
|
||||
|
||||
LOG.info("Webservice called with params: %s", params)
|
||||
|
||||
path = ("plugin://plugin.video.emby?mode=play&id=%s&dbid=%s&filename=%s&transcode=%s"
|
||||
% (params.get('Id'), params.get('KodiId'), params.get('Name'), params.get('transcode') or False))
|
||||
|
||||
self.send_response(200)
|
||||
self.send_header('Content-type', 'text/html')
|
||||
self.send_header('Content-Length', len(path))
|
||||
self.end_headers()
|
||||
|
||||
if not headers_only:
|
||||
self.wfile.write(path)
|
||||
except IndexError as error:
|
||||
|
||||
LOG.error(error)
|
||||
self.send_error(403)
|
||||
|
||||
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
|
||||
del self.root
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue