Merge pull request #1674 from croneter/py3-fix-socketserver
Fix Plex Companion not working by fixing some issues with PKC's http.server's BaseHTTPRequestHandler
This commit is contained in:
commit
937265dfc9
9 changed files with 194 additions and 99 deletions
|
@ -29,7 +29,6 @@ def getXArgsDeviceInfo(options=None, include_token=True):
|
||||||
"""
|
"""
|
||||||
xargs = {
|
xargs = {
|
||||||
'Accept': '*/*',
|
'Accept': '*/*',
|
||||||
'Connection': 'keep-alive',
|
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
# "Access-Control-Allow-Origin": "*",
|
# "Access-Control-Allow-Origin": "*",
|
||||||
'Accept-Language': xbmc.getLanguage(xbmc.ISO_639_1),
|
'Accept-Language': xbmc.getLanguage(xbmc.ISO_639_1),
|
||||||
|
@ -42,6 +41,8 @@ def getXArgsDeviceInfo(options=None, include_token=True):
|
||||||
'X-Plex-Version': v.ADDON_VERSION,
|
'X-Plex-Version': v.ADDON_VERSION,
|
||||||
'X-Plex-Client-Identifier': getDeviceId(),
|
'X-Plex-Client-Identifier': getDeviceId(),
|
||||||
'X-Plex-Provides': 'client,controller,player,pubsub-player',
|
'X-Plex-Provides': 'client,controller,player,pubsub-player',
|
||||||
|
'X-Plex-Protocol': '1.0',
|
||||||
|
'Cache-Control': 'no-cache'
|
||||||
}
|
}
|
||||||
if include_token and utils.window('pms_token'):
|
if include_token and utils.window('pms_token'):
|
||||||
xargs['X-Plex-Token'] = utils.window('pms_token')
|
xargs['X-Plex-Token'] = utils.window('pms_token')
|
||||||
|
|
|
@ -429,6 +429,15 @@ def get_current_audio_stream_index(playerid):
|
||||||
'properties': ['currentaudiostream']})['result']['currentaudiostream']['index']
|
'properties': ['currentaudiostream']})['result']['currentaudiostream']['index']
|
||||||
|
|
||||||
|
|
||||||
|
def get_current_video_stream_index(playerid):
|
||||||
|
"""
|
||||||
|
Returns the currently active video stream index [int]
|
||||||
|
"""
|
||||||
|
return JsonRPC('Player.GetProperties').execute({
|
||||||
|
'playerid': playerid,
|
||||||
|
'properties': ['currentvideostream']})['result']['currentvideostream']['index']
|
||||||
|
|
||||||
|
|
||||||
def get_current_subtitle_stream_index(playerid):
|
def get_current_subtitle_stream_index(playerid):
|
||||||
"""
|
"""
|
||||||
Returns the currently active subtitle stream index [int] or None if there
|
Returns the currently active subtitle stream index [int] or None if there
|
||||||
|
|
|
@ -390,6 +390,8 @@ class KodiMonitor(xbmc.Monitor):
|
||||||
if not self._switched_to_plex_streams:
|
if not self._switched_to_plex_streams:
|
||||||
# We need to switch to the Plex streams ONCE upon playback start
|
# We need to switch to the Plex streams ONCE upon playback start
|
||||||
# after onavchange has been fired
|
# after onavchange has been fired
|
||||||
|
item.init_kodi_streams()
|
||||||
|
item.switch_to_plex_stream('video')
|
||||||
if utils.settings('audioStreamPick') == '0':
|
if utils.settings('audioStreamPick') == '0':
|
||||||
item.switch_to_plex_stream('audio')
|
item.switch_to_plex_stream('audio')
|
||||||
if utils.settings('subtitleStreamPick') == '0':
|
if utils.settings('subtitleStreamPick') == '0':
|
||||||
|
|
|
@ -179,9 +179,11 @@ class PlaylistItem(object):
|
||||||
# Get the Plex audio and subtitle streams in the same order as Kodi
|
# Get the Plex audio and subtitle streams in the same order as Kodi
|
||||||
# uses them (Kodi uses indexes to activate them, not ids like Plex)
|
# uses them (Kodi uses indexes to activate them, not ids like Plex)
|
||||||
self._streams_have_been_processed = False
|
self._streams_have_been_processed = False
|
||||||
|
self._video_streams = None
|
||||||
self._audio_streams = None
|
self._audio_streams = None
|
||||||
self._subtitle_streams = None
|
self._subtitle_streams = None
|
||||||
# Which Kodi streams are active?
|
# Which Kodi streams are active?
|
||||||
|
self.current_kodi_video_stream = None
|
||||||
self.current_kodi_audio_stream = None
|
self.current_kodi_audio_stream = None
|
||||||
# False means "deactivated", None means "we do not have a Kodi
|
# False means "deactivated", None means "we do not have a Kodi
|
||||||
# equivalent for this Plex subtitle"
|
# equivalent for this Plex subtitle"
|
||||||
|
@ -201,6 +203,12 @@ class PlaylistItem(object):
|
||||||
def uri(self):
|
def uri(self):
|
||||||
return self._uri
|
return self._uri
|
||||||
|
|
||||||
|
@property
|
||||||
|
def video_streams(self):
|
||||||
|
if not self._streams_have_been_processed:
|
||||||
|
self._process_streams()
|
||||||
|
return self._video_streams
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def audio_streams(self):
|
def audio_streams(self):
|
||||||
if not self._streams_have_been_processed:
|
if not self._streams_have_been_processed:
|
||||||
|
@ -213,6 +221,18 @@ class PlaylistItem(object):
|
||||||
self._process_streams()
|
self._process_streams()
|
||||||
return self._subtitle_streams
|
return self._subtitle_streams
|
||||||
|
|
||||||
|
@property
|
||||||
|
def current_plex_video_stream(self):
|
||||||
|
return self.plex_stream_index(self.current_kodi_video_stream, 'video')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def current_plex_audio_stream(self):
|
||||||
|
return self.plex_stream_index(self.current_kodi_audio_stream, 'audio')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def current_plex_sub_stream(self):
|
||||||
|
return self.plex_stream_index(self.current_kodi_sub_stream, 'subtitle')
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return ("{{"
|
return ("{{"
|
||||||
"'id': {self.id}, "
|
"'id': {self.id}, "
|
||||||
|
@ -244,6 +264,13 @@ class PlaylistItem(object):
|
||||||
# the same in Kodi and Plex
|
# the same in Kodi and Plex
|
||||||
self._audio_streams = [x for x in self.api.plex_media_streams()
|
self._audio_streams = [x for x in self.api.plex_media_streams()
|
||||||
if x.get('streamType') == '2']
|
if x.get('streamType') == '2']
|
||||||
|
# Same for video streams
|
||||||
|
self._video_streams = [x for x in self.api.plex_media_streams()
|
||||||
|
if x.get('streamType') == '1']
|
||||||
|
if len(self._video_streams) == 1:
|
||||||
|
# Add a selected = "1" attribute to let our logic stand!
|
||||||
|
# Missing if there is only 1 video stream present
|
||||||
|
self._video_streams[0].set('selected', '1')
|
||||||
self._streams_have_been_processed = True
|
self._streams_have_been_processed = True
|
||||||
|
|
||||||
def _get_iterator(self, stream_type):
|
def _get_iterator(self, stream_type):
|
||||||
|
@ -251,6 +278,17 @@ class PlaylistItem(object):
|
||||||
return self.audio_streams
|
return self.audio_streams
|
||||||
elif stream_type == 'subtitle':
|
elif stream_type == 'subtitle':
|
||||||
return self.subtitle_streams
|
return self.subtitle_streams
|
||||||
|
elif stream_type == 'video':
|
||||||
|
return self.video_streams
|
||||||
|
|
||||||
|
def init_kodi_streams(self):
|
||||||
|
"""
|
||||||
|
Initializes all streams after Kodi has started playing this video
|
||||||
|
"""
|
||||||
|
self.current_kodi_video_stream = js.get_current_video_stream_index(v.KODI_VIDEO_PLAYER_ID)
|
||||||
|
self.current_kodi_audio_stream = js.get_current_audio_stream_index(v.KODI_VIDEO_PLAYER_ID)
|
||||||
|
self.current_kodi_sub_stream = False if not js.get_subtitle_enabled(v.KODI_VIDEO_PLAYER_ID) \
|
||||||
|
else js.get_current_subtitle_stream_index(v.KODI_VIDEO_PLAYER_ID)
|
||||||
|
|
||||||
def plex_stream_index(self, kodi_stream_index, stream_type):
|
def plex_stream_index(self, kodi_stream_index, stream_type):
|
||||||
"""
|
"""
|
||||||
|
@ -261,6 +299,8 @@ class PlaylistItem(object):
|
||||||
"""
|
"""
|
||||||
if stream_type == 'audio':
|
if stream_type == 'audio':
|
||||||
return int(self.audio_streams[kodi_stream_index].get('id'))
|
return int(self.audio_streams[kodi_stream_index].get('id'))
|
||||||
|
elif stream_type == 'video':
|
||||||
|
return int(self.video_streams[kodi_stream_index].get('id'))
|
||||||
elif stream_type == 'subtitle':
|
elif stream_type == 'subtitle':
|
||||||
try:
|
try:
|
||||||
return int(self.subtitle_streams[kodi_stream_index].get('id'))
|
return int(self.subtitle_streams[kodi_stream_index].get('id'))
|
||||||
|
@ -324,10 +364,39 @@ class PlaylistItem(object):
|
||||||
PF.change_audio_stream(plex_stream_index, self.api.part_id())
|
PF.change_audio_stream(plex_stream_index, self.api.part_id())
|
||||||
self.current_kodi_audio_stream = kodi_stream_index
|
self.current_kodi_audio_stream = kodi_stream_index
|
||||||
|
|
||||||
|
def on_kodi_video_stream_change(self, kodi_stream_index):
|
||||||
|
"""
|
||||||
|
Call this method if Kodi changed its video stream and you want Plex to
|
||||||
|
know. kodi_stream_index [int]
|
||||||
|
"""
|
||||||
|
plex_stream_index = int(self.video_streams[kodi_stream_index].get('id'))
|
||||||
|
LOG.debug('Changing Plex video stream to %s, Kodi index %s',
|
||||||
|
plex_stream_index, kodi_stream_index)
|
||||||
|
PF.change_video_stream(plex_stream_index, self.api.part_id())
|
||||||
|
self.current_kodi_video_stream = kodi_stream_index
|
||||||
|
|
||||||
def switch_to_plex_streams(self):
|
def switch_to_plex_streams(self):
|
||||||
|
self.switch_to_plex_stream('video')
|
||||||
self.switch_to_plex_stream('audio')
|
self.switch_to_plex_stream('audio')
|
||||||
self.switch_to_plex_stream('subtitle')
|
self.switch_to_plex_stream('subtitle')
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _set_kodi_stream_if_different(kodi_index, typus):
|
||||||
|
if typus == 'video':
|
||||||
|
current = js.get_current_video_stream_index(v.KODI_VIDEO_PLAYER_ID)
|
||||||
|
if current != kodi_index:
|
||||||
|
LOG.debug('Switching video stream')
|
||||||
|
app.APP.player.setVideoStream(kodi_index)
|
||||||
|
else:
|
||||||
|
LOG.debug('Not switching video stream (no change)')
|
||||||
|
elif typus == 'audio':
|
||||||
|
current = js.get_current_audio_stream_index(v.KODI_VIDEO_PLAYER_ID)
|
||||||
|
if current != kodi_index:
|
||||||
|
LOG.debug('Switching audio stream')
|
||||||
|
app.APP.player.setAudioStream(kodi_index)
|
||||||
|
else:
|
||||||
|
LOG.debug('Not switching audio stream (no change)')
|
||||||
|
|
||||||
def switch_to_plex_stream(self, typus):
|
def switch_to_plex_stream(self, typus):
|
||||||
try:
|
try:
|
||||||
plex_index, language_tag = self.active_plex_stream_index(typus)
|
plex_index, language_tag = self.active_plex_stream_index(typus)
|
||||||
|
@ -351,22 +420,34 @@ class PlaylistItem(object):
|
||||||
# If we're choosing an "illegal" index, this function does
|
# If we're choosing an "illegal" index, this function does
|
||||||
# need seem to fail nor log any errors
|
# need seem to fail nor log any errors
|
||||||
if typus == 'audio':
|
if typus == 'audio':
|
||||||
app.APP.player.setAudioStream(kodi_index)
|
self._set_kodi_stream_if_different(kodi_index, 'audio')
|
||||||
else:
|
elif typus == 'subtitle':
|
||||||
app.APP.player.setSubtitleStream(kodi_index)
|
app.APP.player.setSubtitleStream(kodi_index)
|
||||||
app.APP.player.showSubtitles(True)
|
app.APP.player.showSubtitles(True)
|
||||||
|
elif typus == 'video':
|
||||||
|
self._set_kodi_stream_if_different(kodi_index, 'video')
|
||||||
if typus == 'audio':
|
if typus == 'audio':
|
||||||
self.current_kodi_audio_stream = kodi_index
|
self.current_kodi_audio_stream = kodi_index
|
||||||
else:
|
elif typus == 'subtitle':
|
||||||
self.current_kodi_sub_stream = kodi_index
|
self.current_kodi_sub_stream = kodi_index
|
||||||
|
elif typus == 'video':
|
||||||
|
self.current_kodi_video_stream = kodi_index
|
||||||
|
|
||||||
def on_av_change(self, playerid):
|
def on_av_change(self, playerid):
|
||||||
|
"""
|
||||||
|
Call this method if Kodi reports an "AV-Change"
|
||||||
|
(event "Player.OnAVChange")
|
||||||
|
"""
|
||||||
|
kodi_video_stream = js.get_current_video_stream_index(playerid)
|
||||||
kodi_audio_stream = js.get_current_audio_stream_index(playerid)
|
kodi_audio_stream = js.get_current_audio_stream_index(playerid)
|
||||||
sub_enabled = js.get_subtitle_enabled(playerid)
|
sub_enabled = js.get_subtitle_enabled(playerid)
|
||||||
kodi_sub_stream = js.get_current_subtitle_stream_index(playerid)
|
kodi_sub_stream = js.get_current_subtitle_stream_index(playerid)
|
||||||
# Audio
|
# Audio
|
||||||
if kodi_audio_stream != self.current_kodi_audio_stream:
|
if kodi_audio_stream != self.current_kodi_audio_stream:
|
||||||
self.on_kodi_audio_stream_change(kodi_audio_stream)
|
self.on_kodi_audio_stream_change(kodi_audio_stream)
|
||||||
|
# Video
|
||||||
|
if kodi_video_stream != self.current_kodi_video_stream:
|
||||||
|
self.on_kodi_video_stream_change(kodi_audio_stream)
|
||||||
# Subtitles - CURRENTLY BROKEN ON THE KODI SIDE!
|
# Subtitles - CURRENTLY BROKEN ON THE KODI SIDE!
|
||||||
# current_kodi_sub_stream may also be zero
|
# current_kodi_sub_stream may also be zero
|
||||||
subs_off = (None, False)
|
subs_off = (None, False)
|
||||||
|
@ -376,6 +457,32 @@ class PlaylistItem(object):
|
||||||
and kodi_sub_stream != self.current_kodi_sub_stream)):
|
and kodi_sub_stream != self.current_kodi_sub_stream)):
|
||||||
self.on_kodi_subtitle_stream_change(kodi_sub_stream, sub_enabled)
|
self.on_kodi_subtitle_stream_change(kodi_sub_stream, sub_enabled)
|
||||||
|
|
||||||
|
def on_plex_stream_change(self, plex_data):
|
||||||
|
"""
|
||||||
|
Call this method if Plex Companion wants to change streams
|
||||||
|
"""
|
||||||
|
if 'audioStreamID' in plex_data:
|
||||||
|
plex_index = int(plex_data['audioStreamID'])
|
||||||
|
kodi_index = self.kodi_stream_index(plex_index, 'audio')
|
||||||
|
self._set_kodi_stream_if_different(kodi_index, 'audio')
|
||||||
|
self.current_kodi_audio_stream = kodi_index
|
||||||
|
if 'videoStreamID' in plex_data:
|
||||||
|
plex_index = int(plex_data['videoStreamID'])
|
||||||
|
kodi_index = self.kodi_stream_index(plex_index, 'video')
|
||||||
|
self._set_kodi_stream_if_different(kodi_index, 'video')
|
||||||
|
self.current_kodi_video_stream = kodi_index
|
||||||
|
if 'subtitleStreamID' in plex_data:
|
||||||
|
plex_index = int(plex_data['subtitleStreamID'])
|
||||||
|
if plex_index == 0:
|
||||||
|
app.APP.player.showSubtitles(False)
|
||||||
|
kodi_index = False
|
||||||
|
else:
|
||||||
|
kodi_index = self.kodi_stream_index(plex_index, 'subtitle')
|
||||||
|
if kodi_index:
|
||||||
|
app.APP.player.setSubtitleStream(kodi_index)
|
||||||
|
app.APP.player.showSubtitles(True)
|
||||||
|
self.current_kodi_sub_stream = kodi_index
|
||||||
|
|
||||||
|
|
||||||
def playlist_item_from_kodi(kodi_item):
|
def playlist_item_from_kodi(kodi_item):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -191,19 +191,7 @@ class PlexCompanion(backgroundthread.KillableThread):
|
||||||
playqueue = PQ.get_playqueue_from_type(
|
playqueue = PQ.get_playqueue_from_type(
|
||||||
v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[data['type']])
|
v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[data['type']])
|
||||||
pos = js.get_position(playqueue.playlistid)
|
pos = js.get_position(playqueue.playlistid)
|
||||||
if 'audioStreamID' in data:
|
playqueue.items[pos].on_plex_stream_change(data)
|
||||||
index = playqueue.items[pos].kodi_stream_index(
|
|
||||||
data['audioStreamID'], 'audio')
|
|
||||||
app.APP.player.setAudioStream(index)
|
|
||||||
elif 'subtitleStreamID' in data:
|
|
||||||
if data['subtitleStreamID'] == '0':
|
|
||||||
app.APP.player.showSubtitles(False)
|
|
||||||
else:
|
|
||||||
index = playqueue.items[pos].kodi_stream_index(
|
|
||||||
data['subtitleStreamID'], 'subtitle')
|
|
||||||
app.APP.player.setSubtitleStream(index)
|
|
||||||
else:
|
|
||||||
LOG.error('Unknown setStreams command: %s', data)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _process_refresh(data):
|
def _process_refresh(data):
|
||||||
|
@ -300,7 +288,7 @@ class PlexCompanion(backgroundthread.KillableThread):
|
||||||
start_count = 0
|
start_count = 0
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
httpd = listener.ThreadedHTTPServer(
|
httpd = listener.PKCHTTPServer(
|
||||||
client,
|
client,
|
||||||
subscription_manager,
|
subscription_manager,
|
||||||
('', v.COMPANION_PORT),
|
('', v.COMPANION_PORT),
|
||||||
|
|
|
@ -1148,3 +1148,17 @@ def change_audio_stream(plex_stream_id, part_id):
|
||||||
url = '{server}/library/parts/%s' % part_id
|
url = '{server}/library/parts/%s' % part_id
|
||||||
return DU().downloadUrl(utils.extend_url(url, arguments),
|
return DU().downloadUrl(utils.extend_url(url, arguments),
|
||||||
action_type='PUT')
|
action_type='PUT')
|
||||||
|
|
||||||
|
|
||||||
|
def change_video_stream(plex_stream_id, part_id):
|
||||||
|
"""
|
||||||
|
Tell the PMS to display another video stream
|
||||||
|
- We always do this for ALL parts of a video
|
||||||
|
"""
|
||||||
|
arguments = {
|
||||||
|
'videoStreamID': plex_stream_id,
|
||||||
|
'allParts': 1
|
||||||
|
}
|
||||||
|
url = '{server}/library/parts/%s' % part_id
|
||||||
|
return DU().downloadUrl(utils.extend_url(url, arguments),
|
||||||
|
action_type='PUT')
|
||||||
|
|
|
@ -5,8 +5,7 @@ Plex Companion listener
|
||||||
"""
|
"""
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
from re import sub
|
from re import sub
|
||||||
from socketserver import ThreadingMixIn
|
from http.server import ThreadingHTTPServer, BaseHTTPRequestHandler
|
||||||
from http.server import HTTPServer, BaseHTTPRequestHandler
|
|
||||||
|
|
||||||
from .. import utils, companion, json_rpc as js, clientinfo, variables as v
|
from .. import utils, companion, json_rpc as js, clientinfo, variables as v
|
||||||
from .. import app
|
from .. import app
|
||||||
|
@ -45,7 +44,7 @@ class MyHandler(BaseHTTPRequestHandler):
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.serverlist = []
|
self.serverlist = []
|
||||||
BaseHTTPRequestHandler.__init__(self, *args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
def log_message(self, format, *args):
|
def log_message(self, format, *args):
|
||||||
'''
|
'''
|
||||||
|
@ -62,6 +61,7 @@ class MyHandler(BaseHTTPRequestHandler):
|
||||||
self.answer_request(1)
|
self.answer_request(1)
|
||||||
|
|
||||||
def do_OPTIONS(self):
|
def do_OPTIONS(self):
|
||||||
|
LOG.debug("Serving OPTIONS request...")
|
||||||
self.send_response(200)
|
self.send_response(200)
|
||||||
self.send_header('Content-Length', '0')
|
self.send_header('Content-Length', '0')
|
||||||
self.send_header('X-Plex-Client-Identifier', v.PKC_MACHINE_IDENTIFIER)
|
self.send_header('X-Plex-Client-Identifier', v.PKC_MACHINE_IDENTIFIER)
|
||||||
|
@ -78,24 +78,16 @@ class MyHandler(BaseHTTPRequestHandler):
|
||||||
'x-plex-device-name, x-plex-platform, x-plex-product, accept, '
|
'x-plex-device-name, x-plex-platform, x-plex-product, accept, '
|
||||||
'x-plex-device, x-plex-device-screen-resolution')
|
'x-plex-device, x-plex-device-screen-resolution')
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
self.wfile.close()
|
|
||||||
|
|
||||||
def sendOK(self):
|
|
||||||
self.send_response(200)
|
|
||||||
|
|
||||||
def response(self, body, headers=None, code=200):
|
def response(self, body, headers=None, code=200):
|
||||||
headers = {} if headers is None else headers
|
headers = {} if headers is None else headers
|
||||||
try:
|
|
||||||
self.send_response(code)
|
self.send_response(code)
|
||||||
for key in headers:
|
for key in headers:
|
||||||
self.send_header(key, headers[key])
|
self.send_header(key, headers[key])
|
||||||
self.send_header('Content-Length', len(body))
|
self.send_header('Content-Length', len(body))
|
||||||
self.send_header('Connection', "close")
|
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
|
if body:
|
||||||
self.wfile.write(body.encode('utf-8'))
|
self.wfile.write(body.encode('utf-8'))
|
||||||
self.wfile.close()
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def answer_request(self, send_data):
|
def answer_request(self, send_data):
|
||||||
self.serverlist = self.server.client.getServerList()
|
self.serverlist = self.server.client.getServerList()
|
||||||
|
@ -108,23 +100,37 @@ class MyHandler(BaseHTTPRequestHandler):
|
||||||
params = {}
|
params = {}
|
||||||
for key in paramarrays:
|
for key in paramarrays:
|
||||||
params[key] = paramarrays[key][0]
|
params[key] = paramarrays[key][0]
|
||||||
LOG.debug("remote request_path: %s", request_path)
|
LOG.debug("remote request_path: %s, received from %s with headers: %s",
|
||||||
|
request_path, self.client_address, self.headers.items())
|
||||||
LOG.debug("params received from remote: %s", params)
|
LOG.debug("params received from remote: %s", params)
|
||||||
sub_mgr.update_command_id(self.headers.get(
|
sub_mgr.update_command_id(self.headers.get(
|
||||||
'X-Plex-Client-Identifier', self.client_address[0]),
|
'X-Plex-Client-Identifier', self.client_address[0]),
|
||||||
params.get('commandID'))
|
params.get('commandID'))
|
||||||
|
|
||||||
|
conntype = self.headers.get('Connection', '')
|
||||||
|
if conntype.lower() == 'keep-alive':
|
||||||
|
headers = {
|
||||||
|
'Connection': 'Keep-Alive',
|
||||||
|
'Keep-Alive': 'timeout=20'
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
headers = {'Connection': 'Close'}
|
||||||
|
|
||||||
if request_path == "version":
|
if request_path == "version":
|
||||||
self.response(
|
self.response(
|
||||||
"PlexKodiConnect Plex Companion: Running\nVersion: %s"
|
"PlexKodiConnect Plex Companion: Running\nVersion: %s"
|
||||||
% v.ADDON_VERSION)
|
% v.ADDON_VERSION,
|
||||||
|
headers)
|
||||||
elif request_path == "verify":
|
elif request_path == "verify":
|
||||||
self.response("XBMC JSON connection test:\n" + js.ping())
|
self.response("XBMC JSON connection test:\n" + js.ping(),
|
||||||
|
headers)
|
||||||
elif request_path == 'resources':
|
elif request_path == 'resources':
|
||||||
self.response(
|
self.response(
|
||||||
RESOURCES_XML.format(
|
RESOURCES_XML.format(
|
||||||
title=v.DEVICENAME,
|
title=v.DEVICENAME,
|
||||||
machineIdentifier=v.PKC_MACHINE_IDENTIFIER),
|
machineIdentifier=v.PKC_MACHINE_IDENTIFIER),
|
||||||
clientinfo.getXArgsDeviceInfo(include_token=False))
|
clientinfo.getXArgsDeviceInfo(options=headers,
|
||||||
|
include_token=False))
|
||||||
elif request_path == 'player/timeline/poll':
|
elif request_path == 'player/timeline/poll':
|
||||||
# Plex web does polling if connected to PKC via Companion
|
# Plex web does polling if connected to PKC via Companion
|
||||||
# Only reply if there is indeed something playing
|
# Only reply if there is indeed something playing
|
||||||
|
@ -159,7 +165,7 @@ class MyHandler(BaseHTTPRequestHandler):
|
||||||
'Access-Control-Expose-Headers':
|
'Access-Control-Expose-Headers':
|
||||||
'X-Plex-Client-Identifier',
|
'X-Plex-Client-Identifier',
|
||||||
'Content-Type': 'text/xml;charset=utf-8'
|
'Content-Type': 'text/xml;charset=utf-8'
|
||||||
})
|
}.update(headers))
|
||||||
elif not sub_mgr.stop_sent_to_web:
|
elif not sub_mgr.stop_sent_to_web:
|
||||||
sub_mgr.stop_sent_to_web = True
|
sub_mgr.stop_sent_to_web = True
|
||||||
LOG.debug('Signaling STOP to Plex Web')
|
LOG.debug('Signaling STOP to Plex Web')
|
||||||
|
@ -173,11 +179,11 @@ class MyHandler(BaseHTTPRequestHandler):
|
||||||
'Access-Control-Expose-Headers':
|
'Access-Control-Expose-Headers':
|
||||||
'X-Plex-Client-Identifier',
|
'X-Plex-Client-Identifier',
|
||||||
'Content-Type': 'text/xml;charset=utf-8'
|
'Content-Type': 'text/xml;charset=utf-8'
|
||||||
})
|
}.update(headers))
|
||||||
else:
|
else:
|
||||||
# Fail connection with HTTP 500 error - has been open too long
|
# We're not playing anything yet, just reply with a 200
|
||||||
self.response(
|
self.response(
|
||||||
'Need to close this connection on the PKC side',
|
msg,
|
||||||
{
|
{
|
||||||
'X-Plex-Client-Identifier': v.PKC_MACHINE_IDENTIFIER,
|
'X-Plex-Client-Identifier': v.PKC_MACHINE_IDENTIFIER,
|
||||||
'X-Plex-Protocol': '1.0',
|
'X-Plex-Protocol': '1.0',
|
||||||
|
@ -186,11 +192,12 @@ class MyHandler(BaseHTTPRequestHandler):
|
||||||
'Access-Control-Expose-Headers':
|
'Access-Control-Expose-Headers':
|
||||||
'X-Plex-Client-Identifier',
|
'X-Plex-Client-Identifier',
|
||||||
'Content-Type': 'text/xml;charset=utf-8'
|
'Content-Type': 'text/xml;charset=utf-8'
|
||||||
},
|
}.update(headers))
|
||||||
code=500)
|
|
||||||
elif "/subscribe" in request_path:
|
elif "/subscribe" in request_path:
|
||||||
self.response(v.COMPANION_OK_MESSAGE,
|
headers['Content-Type'] = 'text/xml;charset=utf-8'
|
||||||
clientinfo.getXArgsDeviceInfo(include_token=False))
|
headers = clientinfo.getXArgsDeviceInfo(options=headers,
|
||||||
|
include_token=False)
|
||||||
|
self.response(v.COMPANION_OK_MESSAGE, headers)
|
||||||
protocol = params.get('protocol')
|
protocol = params.get('protocol')
|
||||||
host = self.client_address[0]
|
host = self.client_address[0]
|
||||||
port = params.get('port')
|
port = params.get('port')
|
||||||
|
@ -202,23 +209,23 @@ class MyHandler(BaseHTTPRequestHandler):
|
||||||
uuid,
|
uuid,
|
||||||
command_id)
|
command_id)
|
||||||
elif "/unsubscribe" in request_path:
|
elif "/unsubscribe" in request_path:
|
||||||
self.response(v.COMPANION_OK_MESSAGE,
|
headers['Content-Type'] = 'text/xml;charset=utf-8'
|
||||||
clientinfo.getXArgsDeviceInfo(include_token=False))
|
headers = clientinfo.getXArgsDeviceInfo(options=headers,
|
||||||
|
include_token=False)
|
||||||
|
self.response(v.COMPANION_OK_MESSAGE, headers)
|
||||||
uuid = self.headers.get('X-Plex-Client-Identifier') \
|
uuid = self.headers.get('X-Plex-Client-Identifier') \
|
||||||
or self.client_address[0]
|
or self.client_address[0]
|
||||||
sub_mgr.remove_subscriber(uuid)
|
sub_mgr.remove_subscriber(uuid)
|
||||||
else:
|
else:
|
||||||
# Throw it to companion.py
|
# Throw it to companion.py
|
||||||
companion.process_command(request_path, params)
|
companion.process_command(request_path, params)
|
||||||
self.response('', clientinfo.getXArgsDeviceInfo(include_token=False))
|
headers['Content-Type'] = 'text/xml;charset=utf-8'
|
||||||
|
headers = clientinfo.getXArgsDeviceInfo(options=headers,
|
||||||
|
include_token=False)
|
||||||
|
self.response(v.COMPANION_OK_MESSAGE, headers)
|
||||||
|
|
||||||
|
|
||||||
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
|
class PKCHTTPServer(ThreadingHTTPServer):
|
||||||
"""
|
|
||||||
Using ThreadingMixIn Thread magic
|
|
||||||
"""
|
|
||||||
daemon_threads = True
|
|
||||||
|
|
||||||
def __init__(self, client, subscription_manager, *args, **kwargs):
|
def __init__(self, client, subscription_manager, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
client: Class handle to plexgdm.plexgdm. We can thus ask for an up-to-
|
client: Class handle to plexgdm.plexgdm. We can thus ask for an up-to-
|
||||||
|
@ -228,4 +235,4 @@ class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
|
||||||
"""
|
"""
|
||||||
self.client = client
|
self.client = client
|
||||||
self.subscription_manager = subscription_manager
|
self.subscription_manager = subscription_manager
|
||||||
HTTPServer.__init__(self, *args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
|
@ -93,12 +93,12 @@ class plexgdm(object):
|
||||||
try:
|
try:
|
||||||
log.debug("Sending registration data: HELLO %s\n%s"
|
log.debug("Sending registration data: HELLO %s\n%s"
|
||||||
% (self.client_header, self.client_data))
|
% (self.client_header, self.client_data))
|
||||||
self.update_sock.sendto("HELLO %s\n%s"
|
msg = 'HELLO {}\n{}'.format(self.client_header, self.client_data)
|
||||||
% (self.client_header, self.client_data),
|
self.update_sock.sendto(msg.encode('utf-8'),
|
||||||
self.client_register_group)
|
self.client_register_group)
|
||||||
log.debug('(Re-)registering PKC Plex Companion successful')
|
log.debug('(Re-)registering PKC Plex Companion successful')
|
||||||
except Exception:
|
except Exception as exc:
|
||||||
log.error("Unable to send registration message")
|
log.error("Unable to send registration message. Error: %s", exc)
|
||||||
|
|
||||||
def client_update(self):
|
def client_update(self):
|
||||||
self.update_sock = socket.socket(socket.AF_INET,
|
self.update_sock = socket.socket(socket.AF_INET,
|
||||||
|
|
|
@ -249,27 +249,10 @@ class SubscriptionMgr(object):
|
||||||
answ['token'] = playqueue.plex_transient_token
|
answ['token'] = playqueue.plex_transient_token
|
||||||
# Process audio and subtitle streams
|
# Process audio and subtitle streams
|
||||||
if ptype == v.PLEX_PLAYLIST_TYPE_VIDEO:
|
if ptype == v.PLEX_PLAYLIST_TYPE_VIDEO:
|
||||||
strm_id = self._plex_stream_index(playerid, 'audio')
|
answ['videoStreamID'] = str(item.current_plex_video_stream)
|
||||||
if strm_id:
|
answ['audioStreamID'] = str(item.current_plex_audio_stream)
|
||||||
answ['audioStreamID'] = strm_id
|
# Mind the zero - meaning subs are deactivated
|
||||||
else:
|
answ['subtitleStreamID'] = str(item.current_plex_sub_stream or 0)
|
||||||
LOG.error('We could not select a Plex audiostream')
|
|
||||||
strm_id = self._plex_stream_index(playerid, 'video')
|
|
||||||
if strm_id:
|
|
||||||
answ['videoStreamID'] = strm_id
|
|
||||||
else:
|
|
||||||
LOG.error('We could not select a Plex videostream')
|
|
||||||
if info['subtitleenabled']:
|
|
||||||
try:
|
|
||||||
strm_id = self._plex_stream_index(playerid, 'subtitle')
|
|
||||||
except KeyError:
|
|
||||||
# subtitleenabled can be True while currentsubtitle can
|
|
||||||
# still be {}
|
|
||||||
strm_id = None
|
|
||||||
if strm_id is not None:
|
|
||||||
# If None, then the subtitle is only present on Kodi
|
|
||||||
# side
|
|
||||||
answ['subtitleStreamID'] = strm_id
|
|
||||||
return answ
|
return answ
|
||||||
|
|
||||||
def signal_stop(self):
|
def signal_stop(self):
|
||||||
|
@ -285,22 +268,6 @@ class SubscriptionMgr(object):
|
||||||
self.last_params,
|
self.last_params,
|
||||||
timeout=0.0001)
|
timeout=0.0001)
|
||||||
|
|
||||||
def _plex_stream_index(self, playerid, stream_type):
|
|
||||||
"""
|
|
||||||
Returns the current Plex stream index [str] for the player playerid
|
|
||||||
|
|
||||||
stream_type: 'video', 'audio', 'subtitle'
|
|
||||||
"""
|
|
||||||
playqueue = PQ.PLAYQUEUES[playerid]
|
|
||||||
info = app.PLAYSTATE.player_states[playerid]
|
|
||||||
position = self._get_correct_position(info, playqueue)
|
|
||||||
if info[STREAM_DETAILS[stream_type]] == -1:
|
|
||||||
kodi_stream_index = -1
|
|
||||||
else:
|
|
||||||
kodi_stream_index = info[STREAM_DETAILS[stream_type]]['index']
|
|
||||||
return playqueue.items[position].plex_stream_index(kodi_stream_index,
|
|
||||||
stream_type)
|
|
||||||
|
|
||||||
def update_command_id(self, uuid, command_id):
|
def update_command_id(self, uuid, command_id):
|
||||||
"""
|
"""
|
||||||
Updates the Plex Companien client with the machine identifier uuid with
|
Updates the Plex Companien client with the machine identifier uuid with
|
||||||
|
|
Loading…
Reference in a new issue