commit
6af36be046
6 changed files with 63 additions and 40 deletions
|
@ -1,5 +1,5 @@
|
||||||
[![stable version](https://img.shields.io/badge/stable_version-2.7.1-blue.svg?maxAge=60&style=flat) ](https://github.com/croneter/binary_repo/raw/master/stable/repository.plexkodiconnect/repository.plexkodiconnect-1.0.2.zip)
|
[![stable version](https://img.shields.io/badge/stable_version-2.7.2-blue.svg?maxAge=60&style=flat) ](https://github.com/croneter/binary_repo/raw/master/stable/repository.plexkodiconnect/repository.plexkodiconnect-1.0.2.zip)
|
||||||
[![beta version](https://img.shields.io/badge/beta_version-2.7.1-red.svg?maxAge=60&style=flat) ](https://github.com/croneter/binary_repo/raw/master/beta/repository.plexkodiconnectbeta/repository.plexkodiconnectbeta-1.0.2.zip)
|
[![beta version](https://img.shields.io/badge/beta_version-2.7.2-red.svg?maxAge=60&style=flat) ](https://github.com/croneter/binary_repo/raw/master/beta/repository.plexkodiconnectbeta/repository.plexkodiconnectbeta-1.0.2.zip)
|
||||||
|
|
||||||
[![Installation](https://img.shields.io/badge/wiki-installation-brightgreen.svg?maxAge=60&style=flat)](https://github.com/croneter/PlexKodiConnect/wiki/Installation)
|
[![Installation](https://img.shields.io/badge/wiki-installation-brightgreen.svg?maxAge=60&style=flat)](https://github.com/croneter/PlexKodiConnect/wiki/Installation)
|
||||||
[![FAQ](https://img.shields.io/badge/wiki-FAQ-brightgreen.svg?maxAge=60&style=flat)](https://github.com/croneter/PlexKodiConnect/wiki/faq)
|
[![FAQ](https://img.shields.io/badge/wiki-FAQ-brightgreen.svg?maxAge=60&style=flat)](https://github.com/croneter/PlexKodiConnect/wiki/faq)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
<addon id="plugin.video.plexkodiconnect" name="PlexKodiConnect" version="2.7.1" provider-name="croneter">
|
<addon id="plugin.video.plexkodiconnect" name="PlexKodiConnect" version="2.7.2" provider-name="croneter">
|
||||||
<requires>
|
<requires>
|
||||||
<import addon="xbmc.python" version="2.1.0"/>
|
<import addon="xbmc.python" version="2.1.0"/>
|
||||||
<import addon="script.module.requests" version="2.9.1" />
|
<import addon="script.module.requests" version="2.9.1" />
|
||||||
|
@ -77,7 +77,10 @@
|
||||||
<summary lang="uk_UA">Нативна інтеграція Plex в Kodi</summary>
|
<summary lang="uk_UA">Нативна інтеграція Plex в Kodi</summary>
|
||||||
<description lang="uk_UA">Підключає Kodi до серверу Plex. Цей плагін передбачає, що ви керуєте всіма своїми відео за допомогою Plex (і ніяк не Kodi). Ви можете втратити дані, які вже зберігаються у відео та музичних БД Kodi (оскільки цей плагін безпосередньо їх змінює). Використовуйте на свій страх і ризик!</description>
|
<description lang="uk_UA">Підключає Kodi до серверу Plex. Цей плагін передбачає, що ви керуєте всіма своїми відео за допомогою Plex (і ніяк не Kodi). Ви можете втратити дані, які вже зберігаються у відео та музичних БД Kodi (оскільки цей плагін безпосередньо їх змінює). Використовуйте на свій страх і ризик!</description>
|
||||||
<disclaimer lang="uk_UA">Використовуйте на свій ризик</disclaimer>
|
<disclaimer lang="uk_UA">Використовуйте на свій ризик</disclaimer>
|
||||||
<news>version 2.7.1:
|
<news>version 2.7.2:
|
||||||
|
- Fix Kodi profile switch not working correctly and PKC not exiting cleanly
|
||||||
|
|
||||||
|
version 2.7.1:
|
||||||
- Fix playback not starting at all
|
- Fix playback not starting at all
|
||||||
- Fix rare TypeError: unsupported operand type(s) for /: 'NoneType' and 'int' on playback startup
|
- Fix rare TypeError: unsupported operand type(s) for /: 'NoneType' and 'int' on playback startup
|
||||||
- Improve plex db lookups by creating better db indicees
|
- Improve plex db lookups by creating better db indicees
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
version 2.7.2:
|
||||||
|
- Fix Kodi profile switch not working correctly and PKC not exiting cleanly
|
||||||
|
|
||||||
version 2.7.1:
|
version 2.7.1:
|
||||||
- Fix playback not starting at all
|
- Fix playback not starting at all
|
||||||
- Fix rare TypeError: unsupported operand type(s) for /: 'NoneType' and 'int' on playback startup
|
- Fix rare TypeError: unsupported operand type(s) for /: 'NoneType' and 'int' on playback startup
|
||||||
|
|
|
@ -7,7 +7,9 @@ from __future__ import absolute_import, division, unicode_literals
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
from json import loads
|
from json import loads
|
||||||
import copy
|
import copy
|
||||||
|
|
||||||
import xbmc
|
import xbmc
|
||||||
|
import xbmcgui
|
||||||
|
|
||||||
from .plex_db import PlexDB
|
from .plex_db import PlexDB
|
||||||
from . import kodi_db
|
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 json_rpc as js, playqueue as PQ, playlist_func as PL
|
||||||
from . import backgroundthread, app, variables as v
|
from . import backgroundthread, app, variables as v
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
LOG = getLogger('PLEX.kodimonitor')
|
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):
|
class KodiMonitor(xbmc.Monitor):
|
||||||
|
@ -530,3 +532,36 @@ def _clean_file_table():
|
||||||
LOG.debug('Database was locked, unable to clean file table')
|
LOG.debug('Database was locked, unable to clean file table')
|
||||||
else:
|
else:
|
||||||
LOG.debug('Done cleaning up Kodi file table')
|
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)
|
||||||
|
|
|
@ -4,7 +4,6 @@ from __future__ import absolute_import, division, unicode_literals
|
||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
import xbmc
|
import xbmc
|
||||||
import xbmcgui
|
|
||||||
|
|
||||||
from . import utils, clientinfo, timing
|
from . import utils, clientinfo, timing
|
||||||
from . import initialsetup
|
from . import initialsetup
|
||||||
|
@ -30,12 +29,8 @@ WINDOW_PROPERTIES = (
|
||||||
"pms_token", "plex_token", "plex_authenticated", "plex_restricteduser",
|
"pms_token", "plex_token", "plex_authenticated", "plex_restricteduser",
|
||||||
"plex_allows_mediaDeletion", "plexkodiconnect.command", "plex_result")
|
"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):
|
||||||
class Service():
|
|
||||||
ws = None
|
ws = None
|
||||||
sync = None
|
sync = None
|
||||||
plexcompanion = None
|
plexcompanion = None
|
||||||
|
@ -91,10 +86,6 @@ class Service():
|
||||||
for prop in WINDOW_PROPERTIES:
|
for prop in WINDOW_PROPERTIES:
|
||||||
utils.window(prop, clear=True)
|
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
|
# Load/Reset PKC entirely - important for user/Kodi profile switch
|
||||||
# Clear video nodes properties
|
# Clear video nodes properties
|
||||||
library_sync.VideoNodes().clearProperties()
|
library_sync.VideoNodes().clearProperties()
|
||||||
|
@ -109,6 +100,7 @@ class Service():
|
||||||
self.setup = None
|
self.setup = None
|
||||||
self.alexa = None
|
self.alexa = None
|
||||||
self.playqueue = None
|
self.playqueue = None
|
||||||
|
self.context_monitor = None
|
||||||
# Flags for other threads
|
# Flags for other threads
|
||||||
self.connection_check_running = False
|
self.connection_check_running = False
|
||||||
self.auth_running = False
|
self.auth_running = False
|
||||||
|
@ -406,6 +398,9 @@ class Service():
|
||||||
# Some plumbing
|
# Some plumbing
|
||||||
app.init()
|
app.init()
|
||||||
app.APP.monitor = kodimonitor.KodiMonitor()
|
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()
|
app.APP.player = xbmc.Player()
|
||||||
# Initialize the PKC playqueues
|
# Initialize the PKC playqueues
|
||||||
PQ.init_playqueues()
|
PQ.init_playqueues()
|
||||||
|
@ -423,13 +418,6 @@ class Service():
|
||||||
|
|
||||||
# Main PKC program loop
|
# Main PKC program loop
|
||||||
while not self.isCanceled():
|
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
|
# Check for PKC commands from other Python instances
|
||||||
plex_command = utils.window('plexkodiconnect.command')
|
plex_command = utils.window('plexkodiconnect.command')
|
||||||
|
@ -478,17 +466,6 @@ class Service():
|
||||||
app.APP.monitor.waitForAbort(0.1)
|
app.APP.monitor.waitForAbort(0.1)
|
||||||
continue
|
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:
|
# Before proceeding, need to make sure:
|
||||||
# 1. Server is online
|
# 1. Server is online
|
||||||
# 2. User is set
|
# 2. User is set
|
||||||
|
|
|
@ -48,6 +48,16 @@ class WebSocket(backgroundthread.KillableThread):
|
||||||
def run(self):
|
def run(self):
|
||||||
LOG.info("----===## Starting %s ##===----", self.__class__.__name__)
|
LOG.info("----===## Starting %s ##===----", self.__class__.__name__)
|
||||||
app.APP.register_thread(self)
|
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
|
counter = 0
|
||||||
while not self.isCanceled():
|
while not self.isCanceled():
|
||||||
# In the event the server goes offline
|
# In the event the server goes offline
|
||||||
|
@ -133,11 +143,6 @@ class WebSocket(backgroundthread.KillableThread):
|
||||||
if self.ws is not None:
|
if self.ws is not None:
|
||||||
self.ws.close()
|
self.ws.close()
|
||||||
self.ws = None
|
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):
|
class PMS_Websocket(WebSocket):
|
||||||
|
|
Loading…
Reference in a new issue