Merge branch 'master' into playlists
This commit is contained in:
commit
c5ca8910d7
8 changed files with 62 additions and 34 deletions
|
@ -1,5 +1,5 @@
|
||||||
[![stable version](https://img.shields.io/badge/stable_version-1.8.18-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-1.8.18-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.0.29-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.0.30-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)
|
||||||
|
|
10
addon.xml
10
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.0.29" provider-name="croneter">
|
<addon id="plugin.video.plexkodiconnect" name="PlexKodiConnect" version="2.0.30" 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" />
|
||||||
|
@ -67,7 +67,13 @@
|
||||||
<summary lang="ru_RU">Нативная интеграция сервера Plex в Kodi</summary>
|
<summary lang="ru_RU">Нативная интеграция сервера Plex в Kodi</summary>
|
||||||
<description lang="ru_RU">Подключите Kodi к своему серверу Plex. Плагин предполагает что вы управляете своими видео с помощью Plex (а не в Kodi). Вы можете потерять текущие базы данных музыки и видео в Kodi (так как плагин напрямую их изменяет). Используйте на свой страх и риск</description>
|
<description lang="ru_RU">Подключите Kodi к своему серверу Plex. Плагин предполагает что вы управляете своими видео с помощью Plex (а не в Kodi). Вы можете потерять текущие базы данных музыки и видео в Kodi (так как плагин напрямую их изменяет). Используйте на свой страх и риск</description>
|
||||||
<disclaimer lang="ru_RU">Используйте на свой страх и риск</disclaimer>
|
<disclaimer lang="ru_RU">Используйте на свой страх и риск</disclaimer>
|
||||||
<news>version 2.0.29 (beta only):
|
<news>version 2.0.30 (beta only):
|
||||||
|
- Fix resume for On Deck widget for direct paths
|
||||||
|
- Fix DB reset on Startup if PMS connection fails
|
||||||
|
- Fix searching for PMS if there is no internet connection
|
||||||
|
- Fix context menu missing "Delete item from PMS"
|
||||||
|
|
||||||
|
version 2.0.29 (beta only):
|
||||||
- Fix a racing condition leading to e.g. Plex Companion not working as intended
|
- Fix a racing condition leading to e.g. Plex Companion not working as intended
|
||||||
- Force a sync on startup even if Kodi is playing something
|
- Force a sync on startup even if Kodi is playing something
|
||||||
- Include Plex Home username in "Log-out Plex Home user"
|
- Include Plex Home username in "Log-out Plex Home user"
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
version 2.0.30 (beta only):
|
||||||
|
- Fix resume for On Deck widget for direct paths
|
||||||
|
- Fix DB reset on Startup if PMS connection fails
|
||||||
|
- Fix searching for PMS if there is no internet connection
|
||||||
|
- Fix context menu missing "Delete item from PMS"
|
||||||
|
|
||||||
version 2.0.29 (beta only):
|
version 2.0.29 (beta only):
|
||||||
- Fix a racing condition leading to e.g. Plex Companion not working as intended
|
- Fix a racing condition leading to e.g. Plex Companion not working as intended
|
||||||
- Force a sync on startup even if Kodi is playing something
|
- Force a sync on startup even if Kodi is playing something
|
||||||
|
|
|
@ -112,15 +112,20 @@ class API(object):
|
||||||
"""
|
"""
|
||||||
return self.item.get('ratingKey')
|
return self.item.get('ratingKey')
|
||||||
|
|
||||||
def path(self, force_first_media=True, force_addon=False):
|
def path(self, force_first_media=True, force_addon=False,
|
||||||
|
direct_paths=None):
|
||||||
"""
|
"""
|
||||||
Returns a "fully qualified path": add-on paths or direct paths
|
Returns a "fully qualified path": add-on paths or direct paths
|
||||||
depending on the current settings. Will NOT valide the playurl
|
depending on the current settings. Will NOT valide the playurl
|
||||||
Returns unicode or None if something went wrong.
|
Returns unicode or None if something went wrong.
|
||||||
|
|
||||||
|
Pass direct_path=True if you're calling from another Plex python
|
||||||
|
instance - because otherwise direct paths will evaluate to False!
|
||||||
"""
|
"""
|
||||||
|
direct_paths = direct_paths or state.DIRECT_PATHS
|
||||||
filename = self.file_path(force_first_media=force_first_media)
|
filename = self.file_path(force_first_media=force_first_media)
|
||||||
if (not state.DIRECT_PATHS or force_addon
|
if (not direct_paths or force_addon or
|
||||||
or self.plex_type() == v.PLEX_TYPE_CLIP):
|
self.plex_type() == v.PLEX_TYPE_CLIP):
|
||||||
if filename and '/' in filename:
|
if filename and '/' in filename:
|
||||||
filename = filename.rsplit('/', 1)
|
filename = filename.rsplit('/', 1)
|
||||||
elif filename:
|
elif filename:
|
||||||
|
|
|
@ -330,7 +330,7 @@ def _pms_list_from_plex_tv(token):
|
||||||
xml.attrib
|
xml.attrib
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
LOG.error('Could not get list of PMS from plex.tv')
|
LOG.error('Could not get list of PMS from plex.tv')
|
||||||
return
|
return []
|
||||||
|
|
||||||
from Queue import Queue
|
from Queue import Queue
|
||||||
queue = Queue()
|
queue = Queue()
|
||||||
|
|
|
@ -529,40 +529,45 @@ def getOnDeck(viewid, mediatype, tagname, limit):
|
||||||
xbmcplugin.setContent(HANDLE, 'episodes')
|
xbmcplugin.setContent(HANDLE, 'episodes')
|
||||||
append_show_title = settings('OnDeckTvAppendShow') == 'true'
|
append_show_title = settings('OnDeckTvAppendShow') == 'true'
|
||||||
append_sxxexx = settings('OnDeckTvAppendSeason') == 'true'
|
append_sxxexx = settings('OnDeckTvAppendSeason') == 'true'
|
||||||
directpaths = settings('useDirectPaths') == 'true'
|
|
||||||
if settings('OnDeckTVextended') == 'false':
|
if settings('OnDeckTVextended') == 'false':
|
||||||
# Chances are that this view is used on Kodi startup
|
# Chances are that this view is used on Kodi startup
|
||||||
# Wait till we've connected to a PMS. At most 30s
|
# Wait till we've connected to a PMS. At most 30s
|
||||||
counter = 0
|
counter = 0
|
||||||
while window('plex_authenticated') != 'true':
|
while window('plex_authenticated') != 'true':
|
||||||
counter += 1
|
counter += 1
|
||||||
if counter >= 300:
|
if counter == 300:
|
||||||
log.error('Aborting On Deck view, we were not authenticated '
|
log.error('Aborting On Deck view, we were not authenticated '
|
||||||
'for the PMS')
|
'for the PMS')
|
||||||
return xbmcplugin.endOfDirectory(HANDLE, False)
|
xbmcplugin.endOfDirectory(HANDLE, False)
|
||||||
|
return
|
||||||
sleep(100)
|
sleep(100)
|
||||||
xml = downloadutils.DownloadUtils().downloadUrl(
|
xml = downloadutils.DownloadUtils().downloadUrl(
|
||||||
'{server}/library/sections/%s/onDeck' % viewid)
|
'{server}/library/sections/%s/onDeck' % viewid)
|
||||||
if xml in (None, 401):
|
if xml in (None, 401):
|
||||||
log.error('Could not download PMS xml for view %s' % viewid)
|
log.error('Could not download PMS xml for view %s' % viewid)
|
||||||
return xbmcplugin.endOfDirectory(HANDLE)
|
xbmcplugin.endOfDirectory(HANDLE, False)
|
||||||
limitcounter = 0
|
return
|
||||||
|
direct_paths = settings('useDirectPaths') == '1'
|
||||||
|
counter = 0
|
||||||
for item in xml:
|
for item in xml:
|
||||||
api = API(item)
|
api = API(item)
|
||||||
listitem = api.create_listitem(
|
listitem = api.create_listitem(
|
||||||
append_show_title=append_show_title,
|
append_show_title=append_show_title,
|
||||||
append_sxxexx=append_sxxexx)
|
append_sxxexx=append_sxxexx)
|
||||||
url = api.path()
|
if api.resume_point():
|
||||||
|
listitem.setProperty('resumetime', str(api.resume_point()))
|
||||||
|
path = api.path(force_first_media=False, direct_paths=direct_paths)
|
||||||
xbmcplugin.addDirectoryItem(
|
xbmcplugin.addDirectoryItem(
|
||||||
handle=HANDLE,
|
handle=HANDLE,
|
||||||
url=url,
|
url=path,
|
||||||
listitem=listitem)
|
listitem=listitem)
|
||||||
limitcounter += 1
|
counter += 1
|
||||||
if limitcounter == limit:
|
if counter == limit:
|
||||||
break
|
break
|
||||||
return xbmcplugin.endOfDirectory(
|
xbmcplugin.endOfDirectory(
|
||||||
handle=HANDLE,
|
handle=HANDLE,
|
||||||
cacheToDisc=settings('enableTextureCache') == 'true')
|
cacheToDisc=settings('enableTextureCache') == 'true')
|
||||||
|
return
|
||||||
|
|
||||||
# if the addon is called with nextup parameter,
|
# if the addon is called with nextup parameter,
|
||||||
# we return the nextepisodes list of the given tagname
|
# we return the nextepisodes list of the given tagname
|
||||||
|
@ -661,8 +666,9 @@ def watchlater():
|
||||||
|
|
||||||
log.info('Displaying watch later plex.tv items')
|
log.info('Displaying watch later plex.tv items')
|
||||||
xbmcplugin.setContent(HANDLE, 'movies')
|
xbmcplugin.setContent(HANDLE, 'movies')
|
||||||
|
direct_paths = settings('useDirectPaths') == '1'
|
||||||
for item in xml:
|
for item in xml:
|
||||||
__build_item(item)
|
__build_item(item, direct_paths)
|
||||||
|
|
||||||
xbmcplugin.endOfDirectory(
|
xbmcplugin.endOfDirectory(
|
||||||
handle=HANDLE,
|
handle=HANDLE,
|
||||||
|
@ -715,12 +721,13 @@ def browse_plex(key=None, plex_section_id=None):
|
||||||
artists = False
|
artists = False
|
||||||
albums = False
|
albums = False
|
||||||
musicvideos = False
|
musicvideos = False
|
||||||
|
direct_paths = settings('useDirectPaths') == '1'
|
||||||
for item in xml:
|
for item in xml:
|
||||||
if item.tag == 'Directory':
|
if item.tag == 'Directory':
|
||||||
__build_folder(item, plex_section_id=plex_section_id)
|
__build_folder(item, plex_section_id=plex_section_id)
|
||||||
else:
|
else:
|
||||||
typus = item.attrib.get('type')
|
typus = item.attrib.get('type')
|
||||||
__build_item(item)
|
__build_item(item, direct_paths)
|
||||||
if typus == v.PLEX_TYPE_PHOTO:
|
if typus == v.PLEX_TYPE_PHOTO:
|
||||||
photos = True
|
photos = True
|
||||||
elif typus == v.PLEX_TYPE_MOVIE:
|
elif typus == v.PLEX_TYPE_MOVIE:
|
||||||
|
@ -803,7 +810,7 @@ def __build_folder(xml_element, plex_section_id=None):
|
||||||
listitem=listitem)
|
listitem=listitem)
|
||||||
|
|
||||||
|
|
||||||
def __build_item(xml_element):
|
def __build_item(xml_element, direct_paths):
|
||||||
api = API(xml_element)
|
api = API(xml_element)
|
||||||
listitem = api.create_listitem()
|
listitem = api.create_listitem()
|
||||||
resume = api.resume_point()
|
resume = api.resume_point()
|
||||||
|
@ -820,7 +827,7 @@ def __build_item(xml_element):
|
||||||
elif api.plex_type() == v.PLEX_TYPE_PHOTO:
|
elif api.plex_type() == v.PLEX_TYPE_PHOTO:
|
||||||
url = api.get_picture_path()
|
url = api.get_picture_path()
|
||||||
else:
|
else:
|
||||||
url = api.path()
|
url = api.path(direct_paths=direct_paths)
|
||||||
if api.resume_point():
|
if api.resume_point():
|
||||||
listitem.setProperty('resumetime', str(api.resume_point()))
|
listitem.setProperty('resumetime', str(api.resume_point()))
|
||||||
xbmcplugin.addDirectoryItem(handle=HANDLE,
|
xbmcplugin.addDirectoryItem(handle=HANDLE,
|
||||||
|
|
|
@ -128,10 +128,9 @@ def _write_pms_settings(url, token):
|
||||||
return
|
return
|
||||||
for entry in xml:
|
for entry in xml:
|
||||||
if entry.attrib.get('id', '') == 'allowMediaDeletion':
|
if entry.attrib.get('id', '') == 'allowMediaDeletion':
|
||||||
settings('plex_allows_mediaDeletion',
|
value = 'true' if entry.get('value', '1') == '1' else 'false'
|
||||||
value=entry.attrib.get('value', 'true'))
|
settings('plex_allows_mediaDeletion', value=value)
|
||||||
window('plex_allows_mediaDeletion',
|
window('plex_allows_mediaDeletion', value=value)
|
||||||
value=entry.attrib.get('value', 'true'))
|
|
||||||
|
|
||||||
|
|
||||||
class InitialSetup(object):
|
class InitialSetup(object):
|
||||||
|
|
|
@ -434,9 +434,6 @@ class LibrarySync(Thread):
|
||||||
"""
|
"""
|
||||||
Compare the views to Plex
|
Compare the views to Plex
|
||||||
"""
|
"""
|
||||||
self.views = []
|
|
||||||
vnodes = self.vnodes
|
|
||||||
|
|
||||||
# Get views
|
# Get views
|
||||||
sections = PF.get_plex_sections()
|
sections = PF.get_plex_sections()
|
||||||
try:
|
try:
|
||||||
|
@ -447,6 +444,8 @@ class LibrarySync(Thread):
|
||||||
if state.DIRECT_PATHS is True and state.ENABLE_MUSIC is True:
|
if state.DIRECT_PATHS is True and state.ENABLE_MUSIC is True:
|
||||||
# Will reboot Kodi is new library detected
|
# Will reboot Kodi is new library detected
|
||||||
music.excludefromscan_music_folders(xml=sections)
|
music.excludefromscan_music_folders(xml=sections)
|
||||||
|
self.views = []
|
||||||
|
vnodes = self.vnodes
|
||||||
|
|
||||||
self.nodes = {
|
self.nodes = {
|
||||||
v.PLEX_TYPE_MOVIE: [],
|
v.PLEX_TYPE_MOVIE: [],
|
||||||
|
@ -1528,10 +1527,6 @@ class LibrarySync(Thread):
|
||||||
LOG.info("Db version: %s", settings('dbCreatedWithVersion'))
|
LOG.info("Db version: %s", settings('dbCreatedWithVersion'))
|
||||||
|
|
||||||
LOG.info('Refreshing video nodes and playlists now')
|
LOG.info('Refreshing video nodes and playlists now')
|
||||||
# Completely refresh Kodi playlists and video nodes
|
|
||||||
utils.delete_playlists()
|
|
||||||
utils.delete_nodes()
|
|
||||||
self.maintain_views()
|
|
||||||
# Setup the paths for addon-paths (even when using direct paths)
|
# Setup the paths for addon-paths (even when using direct paths)
|
||||||
with kodidb.GetKodiDB('video') as kodi_db:
|
with kodidb.GetKodiDB('video') as kodi_db:
|
||||||
kodi_db.setup_path_table()
|
kodi_db.setup_path_table()
|
||||||
|
@ -1557,7 +1552,12 @@ class LibrarySync(Thread):
|
||||||
last_time_sync = utils.unix_timestamp()
|
last_time_sync = utils.unix_timestamp()
|
||||||
LOG.info('Initial start-up full sync starting')
|
LOG.info('Initial start-up full sync starting')
|
||||||
xbmc.executebuiltin('InhibitIdleShutdown(true)')
|
xbmc.executebuiltin('InhibitIdleShutdown(true)')
|
||||||
if self.full_sync():
|
# Completely refresh Kodi playlists and video nodes
|
||||||
|
utils.delete_playlists()
|
||||||
|
utils.delete_nodes()
|
||||||
|
if not self.maintain_views():
|
||||||
|
LOG.error('Initial maintain_views not successful')
|
||||||
|
elif self.full_sync():
|
||||||
LOG.info('Initial start-up full sync successful')
|
LOG.info('Initial start-up full sync successful')
|
||||||
settings('SyncInstallRunDone', value='true')
|
settings('SyncInstallRunDone', value='true')
|
||||||
self.install_sync_done = True
|
self.install_sync_done = True
|
||||||
|
@ -1608,7 +1608,12 @@ class LibrarySync(Thread):
|
||||||
if state.SUSPEND_SYNC:
|
if state.SUSPEND_SYNC:
|
||||||
LOG.warning('Forcing startup sync even if Kodi is playing')
|
LOG.warning('Forcing startup sync even if Kodi is playing')
|
||||||
state.SUSPEND_SYNC = False
|
state.SUSPEND_SYNC = False
|
||||||
if self.full_sync():
|
# Completely refresh Kodi playlists and video nodes
|
||||||
|
utils.delete_playlists()
|
||||||
|
utils.delete_nodes()
|
||||||
|
if not self.maintain_views():
|
||||||
|
LOG.info('Initial maintain_views on startup unsuccessful')
|
||||||
|
elif self.full_sync():
|
||||||
initial_sync_done = True
|
initial_sync_done = True
|
||||||
last_sync = utils.unix_timestamp()
|
last_sync = utils.unix_timestamp()
|
||||||
LOG.info('Done initial sync on Kodi startup')
|
LOG.info('Done initial sync on Kodi startup')
|
||||||
|
|
Loading…
Reference in a new issue