From 3c9eb713247e9eaa9c8444c0dcde963a135b07bd Mon Sep 17 00:00:00 2001 From: croneter Date: Thu, 21 Feb 2019 08:47:36 +0100 Subject: [PATCH 1/4] Fix websocket threads not exiting correctly --- resources/lib/websocket_client.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/resources/lib/websocket_client.py b/resources/lib/websocket_client.py index 82c80881..bed6ec4a 100644 --- a/resources/lib/websocket_client.py +++ b/resources/lib/websocket_client.py @@ -48,6 +48,16 @@ class WebSocket(backgroundthread.KillableThread): def run(self): LOG.info("----===## Starting %s ##===----", self.__class__.__name__) app.APP.register_thread(self) + try: + self._run() + finally: + # Close websocket connection on shutdown + if self.ws is not None: + self.ws.close() + app.APP.deregister_thread(self) + LOG.info("##===---- %s Stopped ----===##", self.__class__.__name__) + + def _run(self): counter = 0 while not self.isCanceled(): # In the event the server goes offline @@ -133,11 +143,6 @@ class WebSocket(backgroundthread.KillableThread): if self.ws is not None: self.ws.close() self.ws = None - # Close websocket connection on shutdown - if self.ws is not None: - self.ws.close() - app.APP.deregister_thread(self) - LOG.info("##===---- %s Stopped ----===##", self.__class__.__name__) class PMS_Websocket(WebSocket): From 2c12f2e705f15e1a88281c9cacb78758b4e8579a Mon Sep 17 00:00:00 2001 From: croneter Date: Thu, 21 Feb 2019 08:47:52 +0100 Subject: [PATCH 2/4] Update to new style Python class --- resources/lib/service_entry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/lib/service_entry.py b/resources/lib/service_entry.py index da7966d8..266f466f 100644 --- a/resources/lib/service_entry.py +++ b/resources/lib/service_entry.py @@ -35,7 +35,7 @@ STRINGS = (utils.try_encode(utils.lang(12021)), utils.try_encode(utils.lang(12023))) -class Service(): +class Service(object): ws = None sync = None plexcompanion = None From fa9ca95e2e3b11d50aff87c7c163cce520189406 Mon Sep 17 00:00:00 2001 From: croneter Date: Thu, 21 Feb 2019 09:15:29 +0100 Subject: [PATCH 3/4] Remove obsolete check for Kodi profile switch --- resources/lib/service_entry.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/resources/lib/service_entry.py b/resources/lib/service_entry.py index 266f466f..1e0831f2 100644 --- a/resources/lib/service_entry.py +++ b/resources/lib/service_entry.py @@ -91,10 +91,6 @@ class Service(object): for prop in WINDOW_PROPERTIES: utils.window(prop, clear=True) - # To detect Kodi profile switches - utils.window('plex_kodiProfile', - value=utils.try_decode(xbmc.translatePath("special://profile"))) - # Load/Reset PKC entirely - important for user/Kodi profile switch # Clear video nodes properties library_sync.VideoNodes().clearProperties() @@ -423,13 +419,6 @@ class Service(object): # Main PKC program loop while not self.isCanceled(): - # Check for Kodi profile change - if utils.window('plex_kodiProfile') != v.KODI_PROFILE: - # Profile change happened, terminate this thread and others - LOG.info("Kodi profile was: %s and changed to: %s. " - "Terminating old PlexKodiConnect thread.", - v.KODI_PROFILE, utils.window('plex_kodiProfile')) - break # Check for PKC commands from other Python instances plex_command = utils.window('plexkodiconnect.command') From a9ff70fac7e45cbaae85afe46382d635a5942f5a Mon Sep 17 00:00:00 2001 From: croneter Date: Fri, 22 Feb 2019 07:51:27 +0100 Subject: [PATCH 4/4] Fix PKC not exiting correctly due to a call to xbmc.getCondVisibility --- resources/lib/kodimonitor.py | 41 +++++++++++++++++++++++++++++++--- resources/lib/service_entry.py | 20 ++++------------- 2 files changed, 42 insertions(+), 19 deletions(-) diff --git a/resources/lib/kodimonitor.py b/resources/lib/kodimonitor.py index 16d3da98..d27fb696 100644 --- a/resources/lib/kodimonitor.py +++ b/resources/lib/kodimonitor.py @@ -7,7 +7,9 @@ from __future__ import absolute_import, division, unicode_literals from logging import getLogger from json import loads import copy + import xbmc +import xbmcgui from .plex_db import PlexDB from . import kodi_db @@ -16,11 +18,11 @@ from . import utils, timing, plex_functions as PF, playback from . import json_rpc as js, playqueue as PQ, playlist_func as PL from . import backgroundthread, app, variables as v -############################################################################### - LOG = getLogger('PLEX.kodimonitor') -############################################################################### +# "Start from beginning", "Play from beginning" +STRINGS = (utils.try_encode(utils.lang(12021)), + utils.try_encode(utils.lang(12023))) class KodiMonitor(xbmc.Monitor): @@ -530,3 +532,36 @@ def _clean_file_table(): LOG.debug('Database was locked, unable to clean file table') else: LOG.debug('Done cleaning up Kodi file table') + + +class ContextMonitor(backgroundthread.KillableThread): + """ + Detect the resume dialog for widgets. Could also be used to detect + external players (see Emby implementation) + + Let's not register this thread because it won't quit due to + xbmc.getCondVisibility + It should still exit at some point due to xbmc.abortRequested + """ + def run(self): + LOG.info("----===## Starting ContextMonitor ##===----") + # app.APP.register_thread(self) + try: + self._run() + finally: + # app.APP.deregister_thread(self) + LOG.info("##===---- ContextMonitor Stopped ----===##") + + def _run(self): + while not self.isCanceled(): + # The following function will block if called while PKC should + # exit! + if xbmc.getCondVisibility('Window.IsVisible(DialogContextMenu.xml)'): + if xbmc.getInfoLabel('Control.GetLabel(1002)') in STRINGS: + # Remember that the item IS indeed resumable + control = int(xbmcgui.Window(10106).getFocusId()) + app.PLAYSTATE.resume_playback = True if control == 1001 else False + else: + # Different context menu is displayed + app.PLAYSTATE.resume_playback = False + app.APP.monitor.waitForAbort(0.1) diff --git a/resources/lib/service_entry.py b/resources/lib/service_entry.py index 1e0831f2..7169d0c0 100644 --- a/resources/lib/service_entry.py +++ b/resources/lib/service_entry.py @@ -4,7 +4,6 @@ from __future__ import absolute_import, division, unicode_literals import logging import sys import xbmc -import xbmcgui from . import utils, clientinfo, timing from . import initialsetup @@ -30,10 +29,6 @@ WINDOW_PROPERTIES = ( "pms_token", "plex_token", "plex_authenticated", "plex_restricteduser", "plex_allows_mediaDeletion", "plexkodiconnect.command", "plex_result") -# "Start from beginning", "Play from beginning" -STRINGS = (utils.try_encode(utils.lang(12021)), - utils.try_encode(utils.lang(12023))) - class Service(object): ws = None @@ -105,6 +100,7 @@ class Service(object): self.setup = None self.alexa = None self.playqueue = None + self.context_monitor = None # Flags for other threads self.connection_check_running = False self.auth_running = False @@ -402,6 +398,9 @@ class Service(object): # Some plumbing app.init() app.APP.monitor = kodimonitor.KodiMonitor() + self.context_monitor = kodimonitor.ContextMonitor() + # Start immediately to catch user input even before auth + self.context_monitor.start() app.APP.player = xbmc.Player() # Initialize the PKC playqueues PQ.init_playqueues() @@ -467,17 +466,6 @@ class Service(object): app.APP.monitor.waitForAbort(0.1) continue - # Detect the resume dialog for widgets. Could also be used to detect - # external players (see Emby implementation) - if xbmc.getCondVisibility('Window.IsVisible(DialogContextMenu.xml)'): - if xbmc.getInfoLabel('Control.GetLabel(1002)') in STRINGS: - # Remember that the item IS indeed resumable - control = int(xbmcgui.Window(10106).getFocusId()) - app.PLAYSTATE.resume_playback = True if control == 1001 else False - else: - # Different context menu is displayed - app.PLAYSTATE.resume_playback = False - # Before proceeding, need to make sure: # 1. Server is online # 2. User is set