commit
0373029238
6 changed files with 102 additions and 37 deletions
|
@ -1,5 +1,5 @@
|
|||
[![stable version](https://img.shields.io/badge/stable_version-2.7.8-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.8-red.svg?maxAge=60&style=flat) ](https://github.com/croneter/binary_repo/raw/master/beta/repository.plexkodiconnectbeta/repository.plexkodiconnectbeta-1.0.2.zip)
|
||||
[![stable version](https://img.shields.io/badge/stable_version-2.7.9-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.9-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)
|
||||
[![FAQ](https://img.shields.io/badge/wiki-FAQ-brightgreen.svg?maxAge=60&style=flat)](https://github.com/croneter/PlexKodiConnect/wiki/faq)
|
||||
|
|
10
addon.xml
10
addon.xml
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<addon id="plugin.video.plexkodiconnect" name="PlexKodiConnect" version="2.7.8" provider-name="croneter">
|
||||
<addon id="plugin.video.plexkodiconnect" name="PlexKodiConnect" version="2.7.9" provider-name="croneter">
|
||||
<requires>
|
||||
<import addon="xbmc.python" version="2.1.0"/>
|
||||
<import addon="script.module.requests" version="2.9.1" />
|
||||
|
@ -77,7 +77,13 @@
|
|||
<summary lang="uk_UA">Нативна інтеграція Plex в Kodi</summary>
|
||||
<description lang="uk_UA">Підключає Kodi до серверу Plex. Цей плагін передбачає, що ви керуєте всіма своїми відео за допомогою Plex (і ніяк не Kodi). Ви можете втратити дані, які вже зберігаються у відео та музичних БД Kodi (оскільки цей плагін безпосередньо їх змінює). Використовуйте на свій страх і ризик!</description>
|
||||
<disclaimer lang="uk_UA">Використовуйте на свій ризик</disclaimer>
|
||||
<news>version 2.7.8:
|
||||
<news>version 2.7.9:
|
||||
- Wait for PKC to authorize before loading widgets
|
||||
- Fix UnicodeDecodeError for libraries with non-ASCII paths
|
||||
- Fix TypeError on Kodi start
|
||||
- Fix Kodi Masterlock for nfs paths (requires restart)
|
||||
|
||||
version 2.7.8:
|
||||
- Fix widgets not working in some cases like NVidia Shield
|
||||
- Fix appending of show title, season and episode number
|
||||
- Fix node paths for skins
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
version 2.7.9:
|
||||
- Wait for PKC to authorize before loading widgets
|
||||
- Fix UnicodeDecodeError for libraries with non-ASCII paths
|
||||
- Fix TypeError on Kodi start
|
||||
- Fix Kodi Masterlock for nfs paths (requires restart)
|
||||
|
||||
version 2.7.8:
|
||||
- Fix widgets not working in some cases like NVidia Shield
|
||||
- Fix appending of show title, season and episode number
|
||||
|
|
|
@ -57,6 +57,30 @@ def guess_content_type():
|
|||
return content_type
|
||||
|
||||
|
||||
def _wait_for_auth():
|
||||
"""
|
||||
Call to be sure that PKC is authenticated, e.g. for widgets on Kodi startup.
|
||||
Will wait for at most 30s, then fail if not authenticated. Will set
|
||||
xbmcplugin.endOfDirectory(int(argv[1]), False) if failed
|
||||
|
||||
WARNING - this will potentially stall the shutdown of Kodi since we cannot
|
||||
poll xbmc.Monitor().abortRequested() or waitForAbort() or
|
||||
xbmc.abortRequested
|
||||
"""
|
||||
counter = 0
|
||||
startupdelay = int(utils.settings('startupDelay') or 0)
|
||||
# Wait for <startupdelay in seconds> + 10 seconds at most
|
||||
startupdelay = 10 * startupdelay + 100
|
||||
while utils.window('plex_authenticated') != 'true':
|
||||
counter += 1
|
||||
if counter == startupdelay:
|
||||
LOG.error('Aborting view, we were not authenticated for PMS')
|
||||
xbmcplugin.endOfDirectory(int(sys.argv[1]), False)
|
||||
return False
|
||||
xbmc.sleep(100)
|
||||
return True
|
||||
|
||||
|
||||
def directory_item(label, path, folder=True):
|
||||
"""
|
||||
Adds a xbmcplugin.addDirectoryItem() directory itemlistitem
|
||||
|
@ -228,6 +252,8 @@ def get_video_files(plex_id, params):
|
|||
if plex_id is None:
|
||||
LOG.info('No Plex ID found, abort getting Extras')
|
||||
return xbmcplugin.endOfDirectory(int(sys.argv[1]))
|
||||
if not _wait_for_auth():
|
||||
return xbmcplugin.endOfDirectory(int(sys.argv[1]), False)
|
||||
app.init(entrypoint=True)
|
||||
item = PF.GetPlexMetadata(plex_id)
|
||||
try:
|
||||
|
@ -285,6 +311,8 @@ def extra_fanart(plex_id, plex_path):
|
|||
# because of the caching system in xbmc
|
||||
fanart_dir = path_ops.translate_path("special://thumbnails/plex/%s/"
|
||||
% plex_id)
|
||||
if not _wait_for_auth():
|
||||
return xbmcplugin.endOfDirectory(int(sys.argv[1]), False)
|
||||
if not path_ops.exists(fanart_dir):
|
||||
# Download the images to the cache directory
|
||||
path_ops.makedirs(fanart_dir)
|
||||
|
@ -329,6 +357,8 @@ def playlists(content_type):
|
|||
"""
|
||||
content_type = content_type or guess_content_type()
|
||||
LOG.debug('Listing Plex %s playlists', content_type)
|
||||
if not _wait_for_auth():
|
||||
return xbmcplugin.endOfDirectory(int(sys.argv[1]), False)
|
||||
app.init(entrypoint=True)
|
||||
from .playlists.pms import all_playlists
|
||||
xml = all_playlists()
|
||||
|
@ -352,6 +382,8 @@ def hub(content_type):
|
|||
"""
|
||||
content_type = content_type or guess_content_type()
|
||||
LOG.debug('Showing Plex Hub entries for %s', content_type)
|
||||
if not _wait_for_auth():
|
||||
return xbmcplugin.endOfDirectory(int(sys.argv[1]), False)
|
||||
app.init(entrypoint=True)
|
||||
xml = PF.get_plex_hub()
|
||||
try:
|
||||
|
@ -385,6 +417,8 @@ def watchlater():
|
|||
"""
|
||||
Listing for plex.tv Watch Later section (if signed in to plex.tv)
|
||||
"""
|
||||
if not _wait_for_auth():
|
||||
return xbmcplugin.endOfDirectory(int(sys.argv[1]), False)
|
||||
if utils.window('plex_token') == '':
|
||||
LOG.error('No watch later - not signed in to plex.tv')
|
||||
return xbmcplugin.endOfDirectory(int(sys.argv[1]), False)
|
||||
|
@ -412,6 +446,8 @@ def browse_plex(key=None, plex_type=None, section_id=None, synched=True,
|
|||
"""
|
||||
LOG.debug('Browsing to key %s, section %s, plex_type: %s, synched: %s, '
|
||||
'prompt "%s"', key, section_id, plex_type, synched, prompt)
|
||||
if not _wait_for_auth():
|
||||
return xbmcplugin.endOfDirectory(int(sys.argv[1]), False)
|
||||
app.init(entrypoint=True)
|
||||
if prompt:
|
||||
prompt = utils.dialog('input', prompt)
|
||||
|
@ -429,6 +465,7 @@ def browse_plex(key=None, plex_type=None, section_id=None, synched=True,
|
|||
except AttributeError:
|
||||
LOG.error('Could not browse to key %s, section %s',
|
||||
key, section_id)
|
||||
return
|
||||
show_listing(xml, plex_type, section_id, synched, key)
|
||||
|
||||
|
||||
|
@ -436,6 +473,8 @@ def extras(plex_id):
|
|||
"""
|
||||
Lists all extras for plex_id
|
||||
"""
|
||||
if not _wait_for_auth():
|
||||
return xbmcplugin.endOfDirectory(int(sys.argv[1]), False)
|
||||
app.init(entrypoint=True)
|
||||
xml = PF.GetPlexMetadata(plex_id)
|
||||
try:
|
||||
|
|
|
@ -466,6 +466,31 @@ class InitialSetup(object):
|
|||
server['machineIdentifier'], server['ip'], server['port'],
|
||||
server['scheme'])
|
||||
|
||||
@staticmethod
|
||||
def _add_sources(root, extension):
|
||||
changed = False
|
||||
count = 2
|
||||
for source in root.findall('.//path'):
|
||||
if source.text == extension:
|
||||
count -= 1
|
||||
if count == 0:
|
||||
# sources already set
|
||||
break
|
||||
else:
|
||||
# Missing smb:// occurences, re-add.
|
||||
changed = True
|
||||
for _ in range(0, count):
|
||||
source = etree.SubElement(root, 'source')
|
||||
etree.SubElement(
|
||||
source,
|
||||
'name').text = "PlexKodiConnect Masterlock Hack"
|
||||
etree.SubElement(
|
||||
source,
|
||||
'path',
|
||||
{'pathversion': "1"}).text = extension
|
||||
etree.SubElement(source, 'allowsharing').text = "true"
|
||||
return changed
|
||||
|
||||
def setup(self):
|
||||
"""
|
||||
Initial setup. Run once upon startup.
|
||||
|
@ -507,28 +532,13 @@ class InitialSetup(object):
|
|||
with utils.XmlKodiSetting('sources.xml',
|
||||
force_create=True,
|
||||
top_element='sources') as xml:
|
||||
changed = False
|
||||
for extension in ('smb://', 'nfs://'):
|
||||
root = xml.set_setting(['video'])
|
||||
count = 2
|
||||
for source in root.findall('.//path'):
|
||||
if source.text == "smb://":
|
||||
count -= 1
|
||||
if count == 0:
|
||||
# sources already set
|
||||
break
|
||||
else:
|
||||
# Missing smb:// occurences, re-add.
|
||||
for _ in range(0, count):
|
||||
source = etree.SubElement(root, 'source')
|
||||
etree.SubElement(
|
||||
source,
|
||||
'name').text = "PlexKodiConnect Masterlock Hack"
|
||||
etree.SubElement(
|
||||
source,
|
||||
'path',
|
||||
{'pathversion': "1"}).text = "smb://"
|
||||
etree.SubElement(source, 'allowsharing').text = "true"
|
||||
if reboot is False:
|
||||
reboot = xml.write_xml
|
||||
changed = self._add_sources(root, extension) or changed
|
||||
if changed:
|
||||
xml.write_xml = True
|
||||
reboot = True
|
||||
except utils.ParseError:
|
||||
pass
|
||||
|
||||
|
|
|
@ -57,24 +57,28 @@ def process_method_on_list(method_to_run, items):
|
|||
|
||||
|
||||
def get_clean_image(image):
|
||||
'''helper to strip all kodi tags/formatting of an image path/url'''
|
||||
'''
|
||||
helper to strip all kodi tags/formatting of an image path/url
|
||||
Pass in either unicode or str; returns unicode
|
||||
'''
|
||||
if not image:
|
||||
return ""
|
||||
if "music@" in image:
|
||||
if not isinstance(image, str):
|
||||
image = image.encode('utf-8')
|
||||
if b"music@" in image:
|
||||
# fix for embedded images
|
||||
thumbcache = xbmc.getCacheThumbName(image).replace(".tbn", ".jpg")
|
||||
thumbcache = "special://thumbnails/%s/%s" % (thumbcache[0], thumbcache)
|
||||
thumbcache = xbmc.getCacheThumbName(image)
|
||||
thumbcache = thumbcache.replace(b".tbn", b".jpg")
|
||||
thumbcache = b"special://thumbnails/%s/%s" % (thumbcache[0], thumbcache)
|
||||
if not xbmcvfs.exists(thumbcache):
|
||||
xbmcvfs.copy(image, thumbcache)
|
||||
image = thumbcache
|
||||
if image and "image://" in image:
|
||||
image = image.replace("image://", "")
|
||||
image = urllib.unquote(image.encode("utf-8"))
|
||||
if image.endswith("/"):
|
||||
if image and b"image://" in image:
|
||||
image = image.replace(b"image://", b"")
|
||||
image = urllib.unquote(image)
|
||||
if image.endswith(b"/"):
|
||||
image = image[:-1]
|
||||
if not isinstance(image, unicode):
|
||||
image = image.decode("utf8")
|
||||
return image
|
||||
return image.decode('utf-8')
|
||||
|
||||
|
||||
def generate_item(xml_element):
|
||||
|
|
Loading…
Reference in a new issue