commit
34bc708d7b
12 changed files with 100 additions and 60 deletions
|
@ -1,5 +1,5 @@
|
||||||
[![stable version](https://img.shields.io/badge/stable_version-2.7.6-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.7-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.6-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.7-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)
|
||||||
|
|
12
addon.xml
12
addon.xml
|
@ -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.6" provider-name="croneter">
|
<addon id="plugin.video.plexkodiconnect" name="PlexKodiConnect" version="2.7.7" 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,15 @@
|
||||||
<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.6:
|
<news>version 2.7.7:
|
||||||
|
- Fix sync not working due to non-ASCII Plex library names
|
||||||
|
- Fix PKC synching playstate to wrong user on profile switch. Be aware that Kodi profile switches are error-prone
|
||||||
|
- Fix playback sometimes not being reported for direct paths
|
||||||
|
- Fix float() argument must be a string or a number
|
||||||
|
- Fix nodes for skin use
|
||||||
|
- Fix 'NoneType' object has no attribute 'kodi_path'
|
||||||
|
|
||||||
|
version 2.7.6:
|
||||||
- Make 2.7.5 available for everyone
|
- Make 2.7.5 available for everyone
|
||||||
|
|
||||||
version 2.7.5:
|
version 2.7.5:
|
||||||
|
|
|
@ -1,3 +1,11 @@
|
||||||
|
version 2.7.7:
|
||||||
|
- Fix sync not working due to non-ASCII Plex library names
|
||||||
|
- Fix PKC synching playstate to wrong user on profile switch. Be aware that Kodi profile switches are error-prone
|
||||||
|
- Fix playback sometimes not being reported for direct paths
|
||||||
|
- Fix float() argument must be a string or a number
|
||||||
|
- Fix nodes for skin use
|
||||||
|
- Fix 'NoneType' object has no attribute 'kodi_path'
|
||||||
|
|
||||||
version 2.7.6:
|
version 2.7.6:
|
||||||
- Make 2.7.5 available for everyone
|
- Make 2.7.5 available for everyone
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,7 @@ def show_main_menu(content_type=None):
|
||||||
# Get nodes from the window props
|
# Get nodes from the window props
|
||||||
totalnodes = int(utils.window('Plex.nodes.total') or 0)
|
totalnodes = int(utils.window('Plex.nodes.total') or 0)
|
||||||
for i in range(totalnodes):
|
for i in range(totalnodes):
|
||||||
path = utils.window('Plex.nodes.%s.content' % i)
|
path = utils.window('Plex.nodes.%s.index' % i)
|
||||||
if not path:
|
if not path:
|
||||||
continue
|
continue
|
||||||
label = utils.window('Plex.nodes.%s.title' % i)
|
label = utils.window('Plex.nodes.%s.title' % i)
|
||||||
|
@ -114,9 +114,9 @@ def show_main_menu(content_type=None):
|
||||||
continue
|
continue
|
||||||
# Add ANOTHER menu item that uses add-on paths instead of direct
|
# Add ANOTHER menu item that uses add-on paths instead of direct
|
||||||
# paths in order to let the user navigate into all submenus
|
# paths in order to let the user navigate into all submenus
|
||||||
addon_path = utils.window('Plex.nodes.%s.addon_path' % i)
|
addon_index = utils.window('Plex.nodes.%s.addon_index' % i)
|
||||||
# Append "(More...)" to the label
|
# Append "(More...)" to the label
|
||||||
directory_item('%s (%s)' % (label, utils.lang(22082)), addon_path)
|
directory_item('%s (%s)' % (label, utils.lang(22082)), addon_index)
|
||||||
# Playlists
|
# Playlists
|
||||||
if content_type != 'image':
|
if content_type != 'image':
|
||||||
path = 'plugin://%s?mode=playlists' % v.ADDON_ID
|
path = 'plugin://%s?mode=playlists' % v.ADDON_ID
|
||||||
|
|
|
@ -22,12 +22,9 @@ def kodiid_from_filename(path, kodi_type=None, db_type=None):
|
||||||
"""
|
"""
|
||||||
kodi_id = None
|
kodi_id = None
|
||||||
path = utils.try_decode(path)
|
path = utils.try_decode(path)
|
||||||
try:
|
path, filename = path_ops.path.split(path)
|
||||||
filename = path.rsplit('/', 1)[1]
|
# Make sure path ends in either '/' or '\'
|
||||||
path = path.rsplit('/', 1)[0] + '/'
|
path = path_ops.path.join(path, '')
|
||||||
except IndexError:
|
|
||||||
filename = path.rsplit('\\', 1)[1]
|
|
||||||
path = path.rsplit('\\', 1)[0] + '\\'
|
|
||||||
if kodi_type == v.KODI_TYPE_SONG or db_type == 'music':
|
if kodi_type == v.KODI_TYPE_SONG or db_type == 'music':
|
||||||
with KodiMusicDB(lock=False) as kodidb:
|
with KodiMusicDB(lock=False) as kodidb:
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -258,6 +258,7 @@ class FullSync(common.fullsync_mixin):
|
||||||
for section in (x for x in sections.SECTIONS
|
for section in (x for x in sections.SECTIONS
|
||||||
if x.section_type == kind[1]):
|
if x.section_type == kind[1]):
|
||||||
if self.isCanceled():
|
if self.isCanceled():
|
||||||
|
LOG.debug('Need to exit now')
|
||||||
return
|
return
|
||||||
if not section.sync_to_kodi:
|
if not section.sync_to_kodi:
|
||||||
LOG.info('User chose to not sync section %s', section)
|
LOG.info('User chose to not sync section %s', section)
|
||||||
|
@ -283,6 +284,8 @@ class FullSync(common.fullsync_mixin):
|
||||||
self.section_success = False
|
self.section_success = False
|
||||||
else:
|
else:
|
||||||
queue.put(element)
|
queue.put(element)
|
||||||
|
except Exception:
|
||||||
|
utils.ERROR(notify=True)
|
||||||
finally:
|
finally:
|
||||||
queue.put(None)
|
queue.put(None)
|
||||||
|
|
||||||
|
@ -410,7 +413,7 @@ class FullSync(common.fullsync_mixin):
|
||||||
def _run(self):
|
def _run(self):
|
||||||
self.current_sync = timing.plex_now()
|
self.current_sync = timing.plex_now()
|
||||||
# Get latest Plex libraries and build playlist and video node files
|
# Get latest Plex libraries and build playlist and video node files
|
||||||
if not sections.sync_from_pms(self):
|
if self.isCanceled() or not sections.sync_from_pms(self):
|
||||||
return
|
return
|
||||||
self.successful = True
|
self.successful = True
|
||||||
try:
|
try:
|
||||||
|
@ -422,10 +425,7 @@ class FullSync(common.fullsync_mixin):
|
||||||
# Actual syncing - do only new items first
|
# Actual syncing - do only new items first
|
||||||
LOG.info('Running full_library_sync with repair=%s',
|
LOG.info('Running full_library_sync with repair=%s',
|
||||||
self.repair)
|
self.repair)
|
||||||
if not self.full_library_sync():
|
if self.isCanceled() or not self.full_library_sync():
|
||||||
self.successful = False
|
|
||||||
return
|
|
||||||
if self.isCanceled():
|
|
||||||
self.successful = False
|
self.successful = False
|
||||||
return
|
return
|
||||||
if common.PLAYLIST_SYNC_ENABLED and not playlists.full_sync():
|
if common.PLAYLIST_SYNC_ENABLED and not playlists.full_sync():
|
||||||
|
@ -437,6 +437,7 @@ class FullSync(common.fullsync_mixin):
|
||||||
self.dialog.close()
|
self.dialog.close()
|
||||||
if self.threader:
|
if self.threader:
|
||||||
self.threader.shutdown()
|
self.threader.shutdown()
|
||||||
|
self.threader = None
|
||||||
if not self.successful and not self.isCanceled():
|
if not self.successful and not self.isCanceled():
|
||||||
# "ERROR in library sync"
|
# "ERROR in library sync"
|
||||||
utils.dialog('notification',
|
utils.dialog('notification',
|
||||||
|
|
|
@ -99,7 +99,7 @@ class Section(object):
|
||||||
"'section_type': '{self.section_type}', "
|
"'section_type': '{self.section_type}', "
|
||||||
"'sync_to_kodi': {self.sync_to_kodi}, "
|
"'sync_to_kodi': {self.sync_to_kodi}, "
|
||||||
"'last_sync': {self.last_sync}"
|
"'last_sync': {self.last_sync}"
|
||||||
"}}").format(self=self)
|
"}}").format(self=self).encode('utf-8')
|
||||||
__str__ = __repr__
|
__str__ = __repr__
|
||||||
|
|
||||||
def __nonzero__(self):
|
def __nonzero__(self):
|
||||||
|
@ -246,20 +246,27 @@ class Section(object):
|
||||||
}
|
}
|
||||||
if not self.sync_to_kodi:
|
if not self.sync_to_kodi:
|
||||||
args['synched'] = 'false'
|
args['synched'] = 'false'
|
||||||
addon_path = self.addon_path(args)
|
addon_index = self.addon_path(args)
|
||||||
if self.sync_to_kodi and self.section_type in v.PLEX_VIDEOTYPES:
|
if self.sync_to_kodi and self.section_type in v.PLEX_VIDEOTYPES:
|
||||||
path = 'library://video/Plex-%s' % self.section_id
|
path = 'library://video/Plex-{0}/{0}_all.xml'
|
||||||
|
path = path.format(self.section_id)
|
||||||
|
index = 'library://video/Plex-%s' % self.section_id
|
||||||
else:
|
else:
|
||||||
# No xmls to link to - let's show the listings on the fly
|
# No xmls to link to - let's show the listings on the fly
|
||||||
path = addon_path
|
index = addon_index
|
||||||
|
args['key'] = '/library/sections/%s/all' % self.section_id
|
||||||
|
path = self.addon_path(args)
|
||||||
|
# .index will list all possible nodes for this library
|
||||||
|
utils.window('%s.index' % self.node, value=index)
|
||||||
utils.window('%s.title' % self.node, value=self.name)
|
utils.window('%s.title' % self.node, value=self.name)
|
||||||
utils.window('%s.type' % self.node, value=self.content)
|
utils.window('%s.type' % self.node, value=self.content)
|
||||||
utils.window('%s.content' % self.node, value=path)
|
utils.window('%s.content' % self.node, value=path)
|
||||||
|
# .path leads to all elements of this library
|
||||||
utils.window('%s.path' % self.node,
|
utils.window('%s.path' % self.node,
|
||||||
value='ActivateWindow(Videos,%s,return)' % path)
|
value='ActivateWindow(Videos,%s,return)' % path)
|
||||||
utils.window('%s.id' % self.node, value=str(self.section_id))
|
utils.window('%s.id' % self.node, value=str(self.section_id))
|
||||||
# To let the user navigate into this node when selecting widgets
|
# To let the user navigate into this node when selecting widgets
|
||||||
utils.window('%s.addon_path' % self.node, value=addon_path)
|
utils.window('%s.addon_index' % self.node, value=addon_index)
|
||||||
if not self.sync_to_kodi:
|
if not self.sync_to_kodi:
|
||||||
self.remove_files_from_kodi()
|
self.remove_files_from_kodi()
|
||||||
return
|
return
|
||||||
|
@ -307,7 +314,7 @@ class Section(object):
|
||||||
xml = getattr(nodes, 'node_%s' % node_type)(self, node_name)
|
xml = getattr(nodes, 'node_%s' % node_type)(self, node_name)
|
||||||
self._write_xml(xml, xml_name)
|
self._write_xml(xml, xml_name)
|
||||||
self.order += 1
|
self.order += 1
|
||||||
self._window_node(path, node_name, node_type)
|
self._window_node(path, node_name, node_type, pms_node)
|
||||||
|
|
||||||
def _write_xml(self, xml, xml_name):
|
def _write_xml(self, xml, xml_name):
|
||||||
LOG.debug('Creating xml for section %s: %s', self.name, xml_name)
|
LOG.debug('Creating xml for section %s: %s', self.name, xml_name)
|
||||||
|
@ -329,17 +336,17 @@ class Section(object):
|
||||||
utils.indent(xml)
|
utils.indent(xml)
|
||||||
etree.ElementTree(xml).write(self.playlist_path, encoding='utf-8')
|
etree.ElementTree(xml).write(self.playlist_path, encoding='utf-8')
|
||||||
|
|
||||||
def _window_node(self, path, node_name, node_type):
|
def _window_node(self, path, node_name, node_type, pms_node):
|
||||||
"""
|
"""
|
||||||
Will save this section's node to the Kodi window variables
|
Will save this section's node to the Kodi window variables
|
||||||
|
|
||||||
Uses the same conventions/logic as Emby for Kodi does
|
Uses the same conventions/logic as Emby for Kodi does
|
||||||
"""
|
"""
|
||||||
if self.section_type == v.PLEX_TYPE_ARTIST:
|
if pms_node or not self.sync_to_kodi:
|
||||||
window_path = 'ActivateWindow(Music,%s,return)' % path
|
|
||||||
elif self.section_type == v.PLEX_TYPE_PHOTO:
|
|
||||||
# Check: elif node_type in ('browse', 'homevideos', 'photos'):
|
# Check: elif node_type in ('browse', 'homevideos', 'photos'):
|
||||||
window_path = path
|
window_path = path
|
||||||
|
elif self.section_type == v.PLEX_TYPE_ARTIST:
|
||||||
|
window_path = 'ActivateWindow(Music,%s,return)' % path
|
||||||
else:
|
else:
|
||||||
window_path = 'ActivateWindow(Videos,%s,return)' % path
|
window_path = 'ActivateWindow(Videos,%s,return)' % path
|
||||||
# if node_type == 'all':
|
# if node_type == 'all':
|
||||||
|
|
|
@ -90,9 +90,9 @@ def sync_pms_time():
|
||||||
# Toggle watched state back
|
# Toggle watched state back
|
||||||
PF.scrobble(plex_id, 'unwatched')
|
PF.scrobble(plex_id, 'unwatched')
|
||||||
try:
|
try:
|
||||||
plextime = xml[0].get('lastViewedAt')
|
plextime = xml[0].attrib['lastViewedAt']
|
||||||
except (IndexError, TypeError, AttributeError):
|
except (IndexError, TypeError, AttributeError, KeyError):
|
||||||
LOG.error('Could not get lastViewedAt - aborting')
|
LOG.warn('Could not get lastViewedAt - aborting')
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Calculate time offset Kodi-PMS
|
# Calculate time offset Kodi-PMS
|
||||||
|
|
|
@ -372,19 +372,15 @@ def verify_kodi_item(plex_id, kodi_item):
|
||||||
raise PlaylistError
|
raise PlaylistError
|
||||||
LOG.debug('Starting research for Kodi id since we didnt get one: %s',
|
LOG.debug('Starting research for Kodi id since we didnt get one: %s',
|
||||||
kodi_item)
|
kodi_item)
|
||||||
kodi_id, _ = kodiid_from_filename(kodi_item['file'],
|
# Try the VIDEO DB first - will find both movies and episodes
|
||||||
v.KODI_TYPE_MOVIE)
|
kodi_id, kodi_type = kodiid_from_filename(kodi_item['file'],
|
||||||
kodi_item['type'] = v.KODI_TYPE_MOVIE
|
db_type='video')
|
||||||
if kodi_id is None:
|
if not kodi_id:
|
||||||
kodi_id, _ = kodiid_from_filename(kodi_item['file'],
|
# No movie or episode found - try MUSIC DB now for songs
|
||||||
v.KODI_TYPE_EPISODE)
|
kodi_id, kodi_type = kodiid_from_filename(kodi_item['file'],
|
||||||
kodi_item['type'] = v.KODI_TYPE_EPISODE
|
db_type='music')
|
||||||
if kodi_id is None:
|
|
||||||
kodi_id, _ = kodiid_from_filename(kodi_item['file'],
|
|
||||||
v.KODI_TYPE_SONG)
|
|
||||||
kodi_item['type'] = v.KODI_TYPE_SONG
|
|
||||||
kodi_item['id'] = kodi_id
|
kodi_item['id'] = kodi_id
|
||||||
kodi_item['type'] = None if kodi_id is None else kodi_item['type']
|
kodi_item['type'] = None if kodi_id is None else kodi_type
|
||||||
LOG.debug('Research results for kodi_item: %s', kodi_item)
|
LOG.debug('Research results for kodi_item: %s', kodi_item)
|
||||||
return kodi_item
|
return kodi_item
|
||||||
|
|
||||||
|
|
|
@ -202,6 +202,8 @@ def _full_sync():
|
||||||
return False
|
return False
|
||||||
playlist = db.get_playlist(plex_id=plex_id)
|
playlist = db.get_playlist(plex_id=plex_id)
|
||||||
LOG.debug('Removing outdated Plex playlist from Kodi: %s', playlist)
|
LOG.debug('Removing outdated Plex playlist from Kodi: %s', playlist)
|
||||||
|
if playlist is None:
|
||||||
|
continue
|
||||||
try:
|
try:
|
||||||
kodi_pl.delete(playlist)
|
kodi_pl.delete(playlist)
|
||||||
except PlaylistError:
|
except PlaylistError:
|
||||||
|
|
|
@ -289,7 +289,9 @@ class SubscriptionMgr(object):
|
||||||
# To avoid RuntimeError, don't use self.lastplayers
|
# To avoid RuntimeError, don't use self.lastplayers
|
||||||
for playerid in (0, 1, 2):
|
for playerid in (0, 1, 2):
|
||||||
self.last_params['state'] = 'stopped'
|
self.last_params['state'] = 'stopped'
|
||||||
self._send_pms_notification(playerid, self.last_params)
|
self._send_pms_notification(playerid,
|
||||||
|
self.last_params,
|
||||||
|
timeout=0.0001)
|
||||||
|
|
||||||
def _plex_stream_index(self, playerid, stream_type):
|
def _plex_stream_index(self, playerid, stream_type):
|
||||||
"""
|
"""
|
||||||
|
@ -399,7 +401,11 @@ class SubscriptionMgr(object):
|
||||||
self.last_params = params
|
self.last_params = params
|
||||||
return params
|
return params
|
||||||
|
|
||||||
def _send_pms_notification(self, playerid, params):
|
def _send_pms_notification(self, playerid, params, timeout=None):
|
||||||
|
"""
|
||||||
|
Pass a really low timeout in seconds if shutting down Kodi and we don't
|
||||||
|
need the PMS' response
|
||||||
|
"""
|
||||||
serv = self._server_by_host(self.server)
|
serv = self._server_by_host(self.server)
|
||||||
playqueue = PQ.PLAYQUEUES[playerid]
|
playqueue = PQ.PLAYQUEUES[playerid]
|
||||||
xargs = params_pms()
|
xargs = params_pms()
|
||||||
|
@ -416,7 +422,8 @@ class SubscriptionMgr(object):
|
||||||
DU().downloadUrl(url,
|
DU().downloadUrl(url,
|
||||||
authenticate=False,
|
authenticate=False,
|
||||||
parameters=xargs,
|
parameters=xargs,
|
||||||
headerOverride=HEADERS_PMS)
|
headerOverride=HEADERS_PMS,
|
||||||
|
timeout=timeout)
|
||||||
LOG.debug("Sent server notification with parameters: %s to %s",
|
LOG.debug("Sent server notification with parameters: %s to %s",
|
||||||
xargs, url)
|
xargs, url)
|
||||||
|
|
||||||
|
|
|
@ -451,12 +451,15 @@ class Service(object):
|
||||||
self.choose_plex_libraries()
|
self.choose_plex_libraries()
|
||||||
elif plex_command == 'RESET-PKC':
|
elif plex_command == 'RESET-PKC':
|
||||||
utils.reset()
|
utils.reset()
|
||||||
|
elif plex_command == 'EXIT-PKC':
|
||||||
|
LOG.info('Received command from another instance to quit')
|
||||||
|
app.APP.stop_pkc = True
|
||||||
if task:
|
if task:
|
||||||
backgroundthread.BGThreader.addTasksToFront([task])
|
backgroundthread.BGThreader.addTasksToFront([task])
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if app.APP.suspend:
|
if app.APP.suspend:
|
||||||
app.APP.monitor.waitForAbort(0.1)
|
xbmc.sleep(100)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Before proceeding, need to make sure:
|
# Before proceeding, need to make sure:
|
||||||
|
@ -495,7 +498,7 @@ class Service(object):
|
||||||
if utils.settings('enable_alexa') == 'true':
|
if utils.settings('enable_alexa') == 'true':
|
||||||
self.alexa.start()
|
self.alexa.start()
|
||||||
|
|
||||||
app.APP.monitor.waitForAbort(0.1)
|
xbmc.sleep(100)
|
||||||
|
|
||||||
# EXITING PKC
|
# EXITING PKC
|
||||||
# Tell all threads to terminate (e.g. several lib sync threads)
|
# Tell all threads to terminate (e.g. several lib sync threads)
|
||||||
|
@ -506,26 +509,37 @@ class Service(object):
|
||||||
library_sync.clear_window_vars()
|
library_sync.clear_window_vars()
|
||||||
# Will block until threads have quit
|
# Will block until threads have quit
|
||||||
app.APP.stop_threads()
|
app.APP.stop_threads()
|
||||||
utils.window('plex_service_started', clear=True)
|
|
||||||
LOG.info("======== STOP %s ========", v.ADDON_NAME)
|
|
||||||
|
|
||||||
|
|
||||||
def start():
|
def start():
|
||||||
# Safety net - Kody starts PKC twice upon first installation!
|
# Safety net - Kody starts PKC twice upon first installation!
|
||||||
if utils.window('plex_service_started') == 'true':
|
if utils.window('plex_service_started') == 'true':
|
||||||
EXIT = True
|
LOG.info('Another service.py instance is already running - shutting '
|
||||||
else:
|
'it down now')
|
||||||
utils.window('plex_service_started', value='true')
|
# Telling the other Python instance of PKC to shut down now
|
||||||
EXIT = False
|
i = 0
|
||||||
|
while utils.window('plexkodiconnect.command'):
|
||||||
# Delay option
|
xbmc.sleep(20)
|
||||||
|
i += 1
|
||||||
|
if i > 300:
|
||||||
|
LOG.error('Could not tell other PKC instance to shut down')
|
||||||
|
return
|
||||||
|
utils.window('plexkodiconnect.command', value='EXIT-PKC')
|
||||||
|
# Telling successful - now wait for actual shut-down
|
||||||
|
i = 0
|
||||||
|
while utils.window('plex_service_started'):
|
||||||
|
xbmc.sleep(20)
|
||||||
|
i += 1
|
||||||
|
if i > 300:
|
||||||
|
LOG.error('Could not shut down other PKC instance')
|
||||||
|
return
|
||||||
|
utils.window('plex_service_started', value='true')
|
||||||
DELAY = int(utils.settings('startupDelay'))
|
DELAY = int(utils.settings('startupDelay'))
|
||||||
|
|
||||||
LOG.info("Delaying Plex startup by: %s sec...", DELAY)
|
LOG.info("Delaying Plex startup by: %s sec...", DELAY)
|
||||||
if EXIT:
|
if DELAY and xbmc.Monitor().waitForAbort(DELAY):
|
||||||
LOG.error('PKC service.py already started - exiting this instance')
|
|
||||||
elif DELAY and xbmc.Monitor().waitForAbort(DELAY):
|
|
||||||
# Start the service
|
# Start the service
|
||||||
LOG.info("Abort requested while waiting. PKC not started.")
|
LOG.info("Abort requested while waiting. PKC not started.")
|
||||||
else:
|
else:
|
||||||
Service().ServiceEntryPoint()
|
Service().ServiceEntryPoint()
|
||||||
|
utils.window('plex_service_started', clear=True)
|
||||||
|
LOG.info("======== STOP PlexKodiConnect service ========")
|
||||||
|
|
Loading…
Reference in a new issue