commit
ee68703da9
10 changed files with 90 additions and 50 deletions
|
@ -1,5 +1,5 @@
|
||||||
[![stable version](https://img.shields.io/badge/stable_version-2.6.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.6.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.6.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.6.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)
|
||||||
|
|
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.6.1" provider-name="croneter">
|
<addon id="plugin.video.plexkodiconnect" name="PlexKodiConnect" version="2.6.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,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.6.1:
|
<news>version 2.6.2:
|
||||||
|
- Fix playlist sync: sequence item 0: expected string or unicode
|
||||||
|
- Fix PKC not deleting all the items it should
|
||||||
|
- Fix keyError 'sessionKey' for weird PMS messages
|
||||||
|
- Fix artwork caching AttributeError: 'ImageCachingThread' object has no attribute 'cancel'
|
||||||
|
- Improve pop-up "Searching for PMS"
|
||||||
|
- Fix FutureWarning
|
||||||
|
|
||||||
|
version 2.6.1:
|
||||||
- WARNING: You will need to reset the Kodi database!
|
- WARNING: You will need to reset the Kodi database!
|
||||||
- Fix TV sections not being deleted e.g. after user switch
|
- Fix TV sections not being deleted e.g. after user switch
|
||||||
- Don't show a library sync error pop-up when full sync is interrupted
|
- Don't show a library sync error pop-up when full sync is interrupted
|
||||||
|
|
|
@ -1,3 +1,11 @@
|
||||||
|
version 2.6.2:
|
||||||
|
- Fix playlist sync: sequence item 0: expected string or unicode
|
||||||
|
- Fix PKC not deleting all the items it should
|
||||||
|
- Fix keyError 'sessionKey' for weird PMS messages
|
||||||
|
- Fix artwork caching AttributeError: 'ImageCachingThread' object has no attribute 'cancel'
|
||||||
|
- Improve pop-up "Searching for PMS"
|
||||||
|
- Fix FutureWarning
|
||||||
|
|
||||||
version 2.6.1:
|
version 2.6.1:
|
||||||
- WARNING: You will need to reset the Kodi database!
|
- WARNING: You will need to reset the Kodi database!
|
||||||
- Fix TV sections not being deleted e.g. after user switch
|
- Fix TV sections not being deleted e.g. after user switch
|
||||||
|
|
|
@ -220,7 +220,7 @@ class InitialSetup(object):
|
||||||
verifySSL=verifySSL)
|
verifySSL=verifySSL)
|
||||||
return chk
|
return chk
|
||||||
|
|
||||||
def pick_pms(self, showDialog=False):
|
def pick_pms(self, showDialog=False, inform_of_search=False):
|
||||||
"""
|
"""
|
||||||
Searches for PMS in local Lan and optionally (if self.plex_token set)
|
Searches for PMS in local Lan and optionally (if self.plex_token set)
|
||||||
also on plex.tv
|
also on plex.tv
|
||||||
|
@ -260,10 +260,10 @@ class InitialSetup(object):
|
||||||
if showDialog is True:
|
if showDialog is True:
|
||||||
server = self._user_pick_pms()
|
server = self._user_pick_pms()
|
||||||
else:
|
else:
|
||||||
server = self._auto_pick_pms()
|
server = self._auto_pick_pms(show_dialog=inform_of_search)
|
||||||
return server
|
return server
|
||||||
|
|
||||||
def _auto_pick_pms(self):
|
def _auto_pick_pms(self, show_dialog=False):
|
||||||
"""
|
"""
|
||||||
Will try to pick PMS based on machineIdentifier saved in file settings
|
Will try to pick PMS based on machineIdentifier saved in file settings
|
||||||
but only once
|
but only once
|
||||||
|
@ -272,35 +272,47 @@ class InitialSetup(object):
|
||||||
"""
|
"""
|
||||||
https_updated = False
|
https_updated = False
|
||||||
server = None
|
server = None
|
||||||
while True:
|
if show_dialog:
|
||||||
if https_updated is False:
|
# Searching for PMS
|
||||||
serverlist = PF.discover_pms(self.plex_token)
|
utils.dialog('notification',
|
||||||
for item in serverlist:
|
heading='{plex}',
|
||||||
if item.get('machineIdentifier') == app.CONN.machine_identifier:
|
message=utils.lang(30001),
|
||||||
server = item
|
icon='{plex}',
|
||||||
if server is None:
|
time=60000)
|
||||||
name = utils.settings('plex_servername')
|
try:
|
||||||
LOG.warn('The PMS you have used before with a unique '
|
while True:
|
||||||
'machineIdentifier of %s and name %s is '
|
if https_updated is False:
|
||||||
'offline', app.CONN.machine_identifier, name)
|
serverlist = PF.discover_pms(self.plex_token)
|
||||||
|
for item in serverlist:
|
||||||
|
if item.get('machineIdentifier') == app.CONN.machine_identifier:
|
||||||
|
server = item
|
||||||
|
if server is None:
|
||||||
|
name = utils.settings('plex_servername')
|
||||||
|
LOG.warn('The PMS you have used before with a unique '
|
||||||
|
'machineIdentifier of %s and name %s is '
|
||||||
|
'offline', app.CONN.machine_identifier, name)
|
||||||
|
return
|
||||||
|
chk = self._check_pms_connectivity(server)
|
||||||
|
if chk == 504 and https_updated is False:
|
||||||
|
# switch HTTPS to HTTP or vice-versa
|
||||||
|
if server['scheme'] == 'https':
|
||||||
|
server['scheme'] = 'http'
|
||||||
|
else:
|
||||||
|
server['scheme'] = 'https'
|
||||||
|
https_updated = True
|
||||||
|
continue
|
||||||
|
# Problems connecting
|
||||||
|
elif chk >= 400 or chk is False:
|
||||||
|
LOG.warn('Problems connecting to server %s. chk is %s',
|
||||||
|
server['name'], chk)
|
||||||
return
|
return
|
||||||
chk = self._check_pms_connectivity(server)
|
LOG.info('We found a server to automatically connect to: %s',
|
||||||
if chk == 504 and https_updated is False:
|
server['name'])
|
||||||
# switch HTTPS to HTTP or vice-versa
|
return server
|
||||||
if server['scheme'] == 'https':
|
finally:
|
||||||
server['scheme'] = 'http'
|
if show_dialog:
|
||||||
else:
|
executebuiltin("Dialog.Close(all, true)")
|
||||||
server['scheme'] = 'https'
|
|
||||||
https_updated = True
|
|
||||||
continue
|
|
||||||
# Problems connecting
|
|
||||||
elif chk >= 400 or chk is False:
|
|
||||||
LOG.warn('Problems connecting to server %s. chk is %s',
|
|
||||||
server['name'], chk)
|
|
||||||
return
|
|
||||||
LOG.info('We found a server to automatically connect to: %s',
|
|
||||||
server['name'])
|
|
||||||
return server
|
|
||||||
|
|
||||||
def _user_pick_pms(self):
|
def _user_pick_pms(self):
|
||||||
"""
|
"""
|
||||||
|
@ -314,7 +326,7 @@ class InitialSetup(object):
|
||||||
heading='{plex}',
|
heading='{plex}',
|
||||||
message=utils.lang(30001),
|
message=utils.lang(30001),
|
||||||
icon='{plex}',
|
icon='{plex}',
|
||||||
time=5000)
|
time=60000)
|
||||||
while True:
|
while True:
|
||||||
if https_updated is False:
|
if https_updated is False:
|
||||||
serverlist = PF.discover_pms(self.plex_token)
|
serverlist = PF.discover_pms(self.plex_token)
|
||||||
|
@ -343,6 +355,8 @@ class InitialSetup(object):
|
||||||
dialoglist.append('%s (%s)'
|
dialoglist.append('%s (%s)'
|
||||||
% (server['name'], msg))
|
% (server['name'], msg))
|
||||||
# Let user pick server from a list
|
# Let user pick server from a list
|
||||||
|
# Close the PKC info "Searching for PMS"
|
||||||
|
executebuiltin("Dialog.Close(all, true)")
|
||||||
resp = utils.dialog('select', utils.lang(39012), dialoglist)
|
resp = utils.dialog('select', utils.lang(39012), dialoglist)
|
||||||
if resp == -1:
|
if resp == -1:
|
||||||
# User cancelled
|
# User cancelled
|
||||||
|
@ -551,7 +565,7 @@ class InitialSetup(object):
|
||||||
if not self.plex_token and app.ACCOUNT.myplexlogin:
|
if not self.plex_token and app.ACCOUNT.myplexlogin:
|
||||||
self.plex_tv_sign_in()
|
self.plex_tv_sign_in()
|
||||||
|
|
||||||
server = self.pick_pms()
|
server = self.pick_pms(inform_of_search=True)
|
||||||
if server is not None:
|
if server is not None:
|
||||||
# Write our chosen server to Kodi settings file
|
# Write our chosen server to Kodi settings file
|
||||||
self.save_pms_settings(server['baseURL'], server['token'])
|
self.save_pms_settings(server['baseURL'], server['token'])
|
||||||
|
|
|
@ -372,12 +372,17 @@ class FullSync(common.fullsync_mixin):
|
||||||
])
|
])
|
||||||
for plex_type, context in kinds:
|
for plex_type, context in kinds:
|
||||||
# Delete movies that are not on Plex anymore
|
# Delete movies that are not on Plex anymore
|
||||||
with context(self.current_sync) as ctx:
|
while True:
|
||||||
for plex_id in ctx.plexdb.plex_id_by_last_sync(plex_type,
|
with context(self.current_sync) as ctx:
|
||||||
self.current_sync):
|
plex_ids = list(ctx.plexdb.plex_id_by_last_sync(plex_type,
|
||||||
if self.isCanceled():
|
self.current_sync,
|
||||||
return False
|
BATCH_SIZE))
|
||||||
ctx.remove(plex_id, plex_type)
|
for plex_id in plex_ids:
|
||||||
|
if self.isCanceled():
|
||||||
|
return False
|
||||||
|
ctx.remove(plex_id, plex_type)
|
||||||
|
if len(plex_ids) < BATCH_SIZE:
|
||||||
|
break
|
||||||
LOG.debug('Done deleting')
|
LOG.debug('Done deleting')
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
|
@ -256,6 +256,9 @@ def process_playing(data):
|
||||||
skip = True
|
skip = True
|
||||||
if skip:
|
if skip:
|
||||||
continue
|
continue
|
||||||
|
if 'sessionKey' not in message:
|
||||||
|
LOG.warn('Received malformed message from the PMS: %s', message)
|
||||||
|
continue
|
||||||
session_key = message['sessionKey']
|
session_key = message['sessionKey']
|
||||||
# Do we already have a sessionKey stored?
|
# Do we already have a sessionKey stored?
|
||||||
if session_key not in PLAYSTATE_SESSIONS:
|
if session_key not in PLAYSTATE_SESSIONS:
|
||||||
|
|
|
@ -108,7 +108,8 @@ def add_items(playlist, plex_ids):
|
||||||
'title': playlist.plex_name,
|
'title': playlist.plex_name,
|
||||||
'smart': 0,
|
'smart': 0,
|
||||||
'uri': ('server://%s/com.plexapp.plugins.library/library/metadata/%s'
|
'uri': ('server://%s/com.plexapp.plugins.library/library/metadata/%s'
|
||||||
% (app.CONN.machine_identifier, ','.join(plex_ids)))
|
% (app.CONN.machine_identifier,
|
||||||
|
','.join(unicode(x) for x in plex_ids)))
|
||||||
}
|
}
|
||||||
xml = DU().downloadUrl(url='{server}/playlists/',
|
xml = DU().downloadUrl(url='{server}/playlists/',
|
||||||
action_type='POST',
|
action_type='POST',
|
||||||
|
|
|
@ -100,13 +100,14 @@ class PlexDBBase(object):
|
||||||
method = getattr(self, 'entry_to_%s' % v.PLEX_TYPE_FROM_KODI_TYPE[kodi_type])
|
method = getattr(self, 'entry_to_%s' % v.PLEX_TYPE_FROM_KODI_TYPE[kodi_type])
|
||||||
return method(self.cursor.fetchone())
|
return method(self.cursor.fetchone())
|
||||||
|
|
||||||
def plex_id_by_last_sync(self, plex_type, last_sync):
|
def plex_id_by_last_sync(self, plex_type, last_sync, limit):
|
||||||
"""
|
"""
|
||||||
Returns an iterator for all items where the last_sync is NOT identical
|
Returns an iterator for all items where the last_sync is NOT identical
|
||||||
"""
|
"""
|
||||||
return (x[0] for x in
|
query = '''
|
||||||
self.cursor.execute('SELECT plex_id FROM %s WHERE last_sync <> ?' % plex_type,
|
SELECT plex_id FROM %s WHERE last_sync <> ? LIMIT %s
|
||||||
(last_sync, )))
|
''' % (plex_type, limit)
|
||||||
|
return (x[0] for x in self.cursor.execute(query, (last_sync, )))
|
||||||
|
|
||||||
def checksum(self, plex_id, plex_type):
|
def checksum(self, plex_id, plex_type):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -264,7 +264,7 @@ def _sign_in_with_pin():
|
||||||
return
|
return
|
||||||
app.APP.monitor.waitForAbort(0.1)
|
app.APP.monitor.waitForAbort(0.1)
|
||||||
if not pinlogin.expired:
|
if not pinlogin.expired:
|
||||||
if pinlogin.xml:
|
if pinlogin.xml is not None:
|
||||||
pin_login_window.setLinking()
|
pin_login_window.setLinking()
|
||||||
return pinlogin.xml
|
return pinlogin.xml
|
||||||
finally:
|
finally:
|
||||||
|
|
|
@ -135,7 +135,7 @@ class Sync(backgroundthread.KillableThread):
|
||||||
LOG.info('Not synching Plex artwork - not caching')
|
LOG.info('Not synching Plex artwork - not caching')
|
||||||
return
|
return
|
||||||
if self.image_cache_thread and self.image_cache_thread.is_alive():
|
if self.image_cache_thread and self.image_cache_thread.is_alive():
|
||||||
self.image_cache_thread.cancel()
|
self.image_cache_thread.abort()
|
||||||
self.image_cache_thread.join()
|
self.image_cache_thread.join()
|
||||||
self.image_cache_thread = artwork.ImageCachingThread()
|
self.image_cache_thread = artwork.ImageCachingThread()
|
||||||
self.image_cache_thread.start()
|
self.image_cache_thread.start()
|
||||||
|
|
Loading…
Reference in a new issue