Merge branch 'hotfixes' into translations

This commit is contained in:
Croneter 2018-04-29 14:40:04 +02:00
commit fae3647407
17 changed files with 308 additions and 195 deletions

View file

@ -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)
[![beta version](https://img.shields.io/badge/beta_version-2.0.19-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.20-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)

View file

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="plugin.video.plexkodiconnect" name="PlexKodiConnect" version="2.0.19" provider-name="croneter">
<addon id="plugin.video.plexkodiconnect" name="PlexKodiConnect" version="2.0.20" provider-name="croneter">
<requires>
<import addon="xbmc.python" version="2.1.0"/>
<import addon="script.module.requests" version="2.9.1" />
<import addon="plugin.video.plexkodiconnect.movies" version="2.0.2" />
<import addon="plugin.video.plexkodiconnect.tvshows" version="2.0.3" />
<import addon="plugin.video.plexkodiconnect.movies" version="2.0.4" />
<import addon="plugin.video.plexkodiconnect.tvshows" version="2.0.4" />
</requires>
<extension point="xbmc.python.pluginsource" library="default.py">
<provides>video audio image</provides>
@ -67,7 +67,14 @@
<summary lang="ru_RU">Нативная интеграция сервера Plex в Kodi</summary>
<description lang="ru_RU">Подключите Kodi к своему серверу Plex. Плагин предполагает что вы управляете своими видео с помощью Plex (а не в Kodi). Вы можете потерять текущие базы данных музыки и видео в Kodi (так как плагин напрямую их изменяет). Используйте на свой страх и риск</description>
<disclaimer lang="ru_RU">Используйте на свой страх и риск</disclaimer>
<news>version 2.0.19 (beta only):
<news>version 2.0.20 (beta only):
- Fix missing episode poster in certain views. You will have to manually reset your Kodi database to benefit
- Fix episode artwork sometimes not being complete
- Fix IndexError for certain Plex channels
- Kodi Leia: Fix playback failing
- Fix TV On Deck direct paths asking to choose between different media
version 2.0.19 (beta only):
- Fix PKC playback startup getting caught in infinity loop
- Rewire library sync, suspend sync during playback
- Fix playback failing in certain cases

View file

@ -1,3 +1,10 @@
version 2.0.20 (beta only):
- Fix missing episode poster in certain views. You will have to manually reset your Kodi database to benefit
- Fix episode artwork sometimes not being complete
- Fix IndexError for certain Plex channels
- Kodi Leia: Fix playback failing
- Fix TV On Deck direct paths asking to choose between different media
version 2.0.19 (beta only):
- Fix PKC playback startup getting caught in infinity loop
- Rewire library sync, suspend sync during playback

View file

@ -41,6 +41,26 @@ msgctxt "#30005"
msgid "Username: "
msgstr ""
# Sync notification displayed if there is still artwork to be cached to Kodi
msgctxt "#30006"
msgid "Caching %s images"
msgstr ""
# Sync notification displayed if syncing of major artwork is done
msgctxt "#30007"
msgid "Major image caching done"
msgstr ""
# PKC settings artwork: Enable notifications for artwork image sync
msgctxt "#30008"
msgid "Enable notifications for image caching"
msgstr ""
# PKC settings artwork: Enable image caching during Kodi playback
msgctxt "#30009"
msgid "Enable image caching during Kodi playback (restart Kodi!)"
msgstr ""
# Button text
msgctxt "#30012"
msgid "OK"

View file

@ -124,8 +124,12 @@ class API(object):
# Local path
filename = ans.rsplit("\\", 1)[1]
else:
# Network share
filename = ans.rsplit("/", 1)[1]
try:
# Network share
filename = ans.rsplit("/", 1)[1]
except IndexError:
# E.g. certain Plex channels
filename = None
return filename
def file_path(self, force_first_media=False):
@ -772,33 +776,41 @@ class API(object):
# Artwork lookup for episodes is broken for addon paths
# Episodes is a bit special, only get the thumb, because all
# the other artwork will be saved under season and show
art = self._one_artwork('thumb')
if art:
artworks['thumb'] = art
if full_artwork:
with plexdb.Get_Plex_DB() as plex_db:
db_item = plex_db.getItem_byId(self.plex_id())
# EXCEPT if you're constructing a listitem
if not full_artwork:
art = self._one_artwork('thumb')
if art:
artworks['thumb'] = art
return artworks
for kodi_artwork, plex_artwork in \
v.KODI_TO_PLEX_ARTWORK_EPISODE.iteritems():
art = self._one_artwork(plex_artwork)
if art:
artworks[kodi_artwork] = art
if not full_artwork:
return artworks
with plexdb.Get_Plex_DB() as plex_db:
try:
season_id = db_item[3]
season_id = plex_db.getItem_byId(self.plex_id())[3]
except TypeError:
return artworks
# Grab artwork from the season
with kodidb.GetKodiDB('video') as kodi_db:
season_art = kodi_db.get_art(season_id, v.KODI_TYPE_SEASON)
for kodi_art in season_art:
artworks['season.%s' % kodi_art] = season_art[kodi_art]
# Get the show id
with plexdb.Get_Plex_DB() as plex_db:
db_item = plex_db.getItem_byId(self.grandparent_id())
# Grab artwork from the season
with kodidb.GetKodiDB('video') as kodi_db:
season_art = kodi_db.get_art(season_id, v.KODI_TYPE_SEASON)
for kodi_art in season_art:
artworks['season.%s' % kodi_art] = season_art[kodi_art]
# Get the show id
with plexdb.Get_Plex_DB() as plex_db:
try:
show_id = db_item[0]
show_id = plex_db.getItem_byKodiId(season_id,
v.KODI_TYPE_SEASON)[1]
except TypeError:
return artworks
# Grab more artwork from the show
with kodidb.GetKodiDB('video') as kodi_db:
show_art = kodi_db.get_art(show_id, v.KODI_TYPE_SHOW)
for kodi_art in show_art:
artworks['tvshow.%s' % kodi_art] = show_art[kodi_art]
# Grab more artwork from the show
with kodidb.GetKodiDB('video') as kodi_db:
show_art = kodi_db.get_art(show_id, v.KODI_TYPE_SHOW)
for kodi_art in show_art:
artworks['tvshow.%s' % kodi_art] = show_art[kodi_art]
return artworks
if kodi_id:
@ -844,7 +856,6 @@ class API(object):
external_id = self.retrieve_external_item_id()
if external_id is not None:
artworks = self.lookup_fanart_tv(external_id[0], artworks)
LOG.debug('fanart artworks: %s', artworks)
return artworks
def retrieve_external_item_id(self, collection=False):

View file

@ -22,6 +22,10 @@ LOG = getLogger("PLEX." + __name__)
# Disable annoying requests warnings
requests.packages.urllib3.disable_warnings()
ARTWORK_QUEUE = Queue()
IMAGE_CACHING_SUSPENDS = ['SUSPEND_LIBRARY_THREAD', 'DB_SCAN', 'STOP_SYNC']
if not settings('imageSyncDuringPlayback') == 'true':
IMAGE_CACHING_SUSPENDS.append('SUSPEND_SYNC')
###############################################################################
@ -33,11 +37,9 @@ def double_urldecode(text):
return unquote(unquote(text))
@thread_methods(add_suspends=['SUSPEND_LIBRARY_THREAD',
'DB_SCAN',
'STOP_SYNC'])
@thread_methods(add_suspends=IMAGE_CACHING_SUSPENDS)
class Image_Cache_Thread(Thread):
sleep_between = 50
sleep_between = 200
# Potentially issues with limited number of threads
# Hence let Kodi wait till download is successful
timeout = (35.1, 35.1)
@ -47,6 +49,7 @@ class Image_Cache_Thread(Thread):
Thread.__init__(self)
def run(self):
LOG.info("---===### Starting Image_Cache_Thread ###===---")
stopped = self.stopped
suspended = self.suspended
queue = self.queue
@ -65,6 +68,16 @@ class Image_Cache_Thread(Thread):
except Empty:
sleep(1000)
continue
if isinstance(url, ArtworkSyncMessage):
if state.IMAGE_SYNC_NOTIFICATIONS:
dialog('notification',
heading=lang(29999),
message=url.message,
icon='{plex}',
sound=False)
queue.task_done()
continue
url = double_urlencode(try_encode(url))
sleeptime = 0
while True:
try:
@ -116,6 +129,44 @@ class Artwork():
if enableTextureCache:
queue = ARTWORK_QUEUE
def cache_major_artwork(self):
"""
Takes the existing Kodi library and caches posters and fanart.
Necessary because otherwise PKC caches artwork e.g. from fanart.tv
which basically blocks Kodi from getting needed artwork fast (e.g.
while browsing the library)
"""
if not self.enableTextureCache:
return
artworks = list()
# Get all posters and fanart/background for video and music
for kind in ('video', 'music'):
connection = kodi_sql(kind)
cursor = connection.cursor()
for typus in ('poster', 'fanart'):
cursor.execute('SELECT url FROM art WHERE type == ?',
(typus, ))
artworks.extend(cursor.fetchall())
connection.close()
artworks_to_cache = list()
connection = kodi_sql('texture')
cursor = connection.cursor()
for url in artworks:
query = 'SELECT url FROM texture WHERE url == ? LIMIT 1'
cursor.execute(query, (url[0], ))
if not cursor.fetchone():
artworks_to_cache.append(url)
connection.close()
if not artworks_to_cache:
LOG.info('Caching of major images to Kodi texture cache done')
return
LOG.info('Caching has not been completed - caching %s major images',
len(artworks_to_cache))
self.queue.put(ArtworkSyncMessage(lang(30006) % len(artworks_to_cache)))
for url in artworks_to_cache:
self.queue.put(url[0])
self.queue.put(ArtworkSyncMessage(lang(30007)))
def fullTextureCacheSync(self):
"""
This method will sync all Kodi artwork to textures13.db
@ -174,10 +225,10 @@ class Artwork():
def cache_texture(self, url):
'''
Cache a single image url to the texture cache
Cache a single image url to the texture cache. url: unicode
'''
if url and self.enableTextureCache:
self.queue.put(double_urlencode(try_encode(url)))
self.queue.put(url)
def modify_artwork(self, artworks, kodi_id, kodi_type, cursor):
"""
@ -266,3 +317,11 @@ class Artwork():
for path in paths:
makedirs(try_decode(translatePath("special://thumbnails/%s"
% path)))
class ArtworkSyncMessage(object):
"""
Put in artwork queue to display the message as a Kodi notification
"""
def __init__(self, message):
self.message = message

View file

@ -369,7 +369,7 @@ def getRecentEpisodes(viewid, mediatype, tagname, limit):
append_show_title = settings('RecentTvAppendShow') == 'true'
append_sxxexx = settings('RecentTvAppendSeason') == 'true'
# First we get a list of all the TV shows - filtered by tag
allshowsIds = set()
allshowsIds = list()
params = {
'sort': {'order': "descending", 'method': "dateadded"},
'filter': {'operator': "is", 'field': "tag", 'value': "%s" % tagname},
@ -553,7 +553,7 @@ def getOnDeck(viewid, mediatype, tagname, limit):
append_show_title=append_show_title,
append_sxxexx=append_sxxexx)
if directpaths:
url = api.file_path()
url = api.file_path(force_first_media=True)
else:
url = ('plugin://%s.tvshows/?plex_id=%s&plex_type=%s&mode=play&filename=%s'
% (v.ADDON_ID,
@ -561,8 +561,7 @@ def getOnDeck(viewid, mediatype, tagname, limit):
api.plex_type(),
api.file_name(force_first_media=True)))
if api.resume_point():
listitem.setProperty('resumetime',
str(api.resume_point()))
listitem.setProperty('resumetime', str(api.resume_point()))
xbmcplugin.addDirectoryItem(
handle=HANDLE,
url=url,

View file

@ -141,7 +141,7 @@ class InitialSetup(object):
"""
def __init__(self):
LOG.debug('Entering initialsetup class')
self.server = UserClient().getServer()
self.server = UserClient().get_server()
self.serverid = settings('plex_machineIdentifier')
# Get Plex credentials from settings file, if they exist
plexdict = PF.GetPlexLoginFromSettings()

View file

@ -1217,6 +1217,7 @@ class Music(Items):
"""
Adds a single music album
children: list of child xml's, so in this case songs
scan_children: set to False if you don't want to add children
"""
kodicursor = self.kodicursor
plex_db = self.plex_db
@ -1224,20 +1225,18 @@ class Music(Items):
api = API(item)
update_item = True
itemid = api.plex_id()
if not itemid:
plex_id = api.plex_id()
if not plex_id:
LOG.error('Error processing Album, skipping')
return
plex_dbitem = plex_db.getItem_byId(itemid)
plex_dbitem = plex_db.getItem_byId(plex_id)
try:
albumid = plex_dbitem[0]
album_id = plex_dbitem[0]
except TypeError:
# Albumid not found
update_item = False
# The album details #####
lastScraped = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
dateadded = api.date_created()
userdata = api.userdata()
checksum = api.checksum()
@ -1269,22 +1268,22 @@ class Music(Items):
# UPDATE THE ALBUM #####
if update_item:
LOG.info("UPDATE album itemid: %s - Name: %s", itemid, name)
LOG.info("UPDATE album plex_id: %s - Name: %s", plex_id, name)
# Update the checksum in plex table
plex_db.updateReference(itemid, checksum)
plex_db.updateReference(plex_id, checksum)
# OR ADD THE ALBUM #####
else:
LOG.info("ADD album itemid: %s - Name: %s", itemid, name)
LOG.info("ADD album plex_id: %s - Name: %s", plex_id, name)
# safety checks: It looks like plex supports the same artist
# multiple times.
# Kodi doesn't allow that. In case that happens we just merge the
# artist entries.
albumid = self.kodi_db.addAlbum(name, musicBrainzId)
album_id = self.kodi_db.addAlbum(name, musicBrainzId)
# Create the reference in plex table
plex_db.addReference(itemid,
plex_db.addReference(plex_id,
v.PLEX_TYPE_ALBUM,
albumid,
album_id,
v.KODI_TYPE_ALBUM,
view_id=viewid,
checksum=checksum)
@ -1302,7 +1301,7 @@ class Music(Items):
kodicursor.execute(query, (artistname, year, self.genre, bio,
thumb, rating, lastScraped,
v.KODI_TYPE_ALBUM, studio,
self.compilation, albumid))
self.compilation, album_id))
elif v.KODIVERSION == 17:
# Kodi Krypton
query = '''
@ -1315,7 +1314,7 @@ class Music(Items):
kodicursor.execute(query, (artistname, year, self.genre, bio,
thumb, rating, lastScraped,
v.KODI_TYPE_ALBUM, studio,
self.compilation, albumid))
self.compilation, album_id))
elif v.KODIVERSION == 16:
# Kodi Jarvis
query = '''
@ -1328,71 +1327,46 @@ class Music(Items):
kodicursor.execute(query, (artistname, year, self.genre, bio,
thumb, rating, lastScraped,
v.KODI_TYPE_ALBUM, studio,
self.compilation, albumid))
self.compilation, album_id))
# Associate the parentid for plex reference
parent_id = api.parent_plex_id()
artist_id = None
if parent_id is not None:
plex_dbartist = plex_db.getItem_byId(parent_id)
try:
artistid = plex_dbartist[0]
artist_id = plex_db.getItem_byId(parent_id)[0]
except TypeError:
LOG.info('Artist %s does not exist in plex database',
parent_id)
LOG.info('Artist %s does not yet exist in Plex DB', parent_id)
artist = GetPlexMetadata(parent_id)
# Item may not be an artist, verification necessary.
if artist is not None and artist != 401:
if artist[0].attrib.get('type') == v.PLEX_TYPE_ARTIST:
# Update with the parent_id, for remove reference
plex_db.addReference(parent_id,
v.PLEX_TYPE_ARTIST,
parent_id,
v.KODI_TYPE_ARTIST,
view_id=viewid)
plex_db.updateParentId(itemid, parent_id)
else:
# Update plex reference with the artistid
plex_db.updateParentId(itemid, artistid)
# Assign main artists to album
# Plex unfortunately only supports 1 artist :-(
artist_id = parent_id
plex_dbartist = plex_db.getItem_byId(artist_id)
try:
artistid = plex_dbartist[0]
except TypeError:
# Artist does not exist in plex database, create the reference
LOG.info('Artist %s does not exist in Plex database', artist_id)
artist = GetPlexMetadata(artist_id)
if artist is not None and artist != 401:
self.add_updateArtist(artist[0])
plex_dbartist = plex_db.getItem_byId(artist_id)
artistid = plex_dbartist[0]
else:
# Best take this name over anything else.
query = "UPDATE artist SET strArtist = ? WHERE idArtist = ?"
kodicursor.execute(query, (artistname, artistid,))
LOG.info("UPDATE artist: strArtist: %s, idArtist: %s",
artistname, artistid)
try:
artist[0].attrib
except (TypeError, IndexError, AttributeError):
LOG.error('Could not get artist xml for %s', parent_id)
else:
self.add_updateArtist(artist[0])
plex_dbartist = plex_db.getItem_byId(parent_id)
try:
artist_id = plex_dbartist[0]
except TypeError:
LOG.error('Adding artist failed for %s', parent_id)
# Update plex reference with the artist_id
plex_db.updateParentId(plex_id, artist_id)
# Add artist to album
query = '''
INSERT OR REPLACE INTO album_artist(idArtist, idAlbum, strArtist)
VALUES (?, ?, ?)
'''
kodicursor.execute(query, (artistid, albumid, artistname))
kodicursor.execute(query, (artist_id, album_id, artistname))
# Update discography
query = '''
INSERT OR REPLACE INTO discography(idArtist, strAlbum, strYear)
VALUES (?, ?, ?)
'''
kodicursor.execute(query, (artistid, name, year))
# Update plex reference with parentid
plex_db.updateParentId(artist_id, albumid)
kodicursor.execute(query, (artist_id, name, year))
if v.KODIVERSION < 18:
self.kodi_db.addMusicGenres(albumid, self.genres, v.KODI_TYPE_ALBUM)
self.kodi_db.addMusicGenres(album_id, self.genres, v.KODI_TYPE_ALBUM)
# Update artwork
artwork.modify_artwork(artworks, albumid, v.KODI_TYPE_ALBUM, kodicursor)
artwork.modify_artwork(artworks, album_id, v.KODI_TYPE_ALBUM, kodicursor)
# Add all children - all tracks
if scan_children:
for child in children:

View file

@ -50,7 +50,8 @@ STATE_SETTINGS = {
'remapSMBphotoNew': 'remapSMBphotoNew',
'enableMusic': 'ENABLE_MUSIC',
'forceReloadSkinOnPlaybackStop': 'FORCE_RELOAD_SKIN',
'fetch_pms_item_number': 'FETCH_PMS_ITEM_NUMBER'
'fetch_pms_item_number': 'FETCH_PMS_ITEM_NUMBER',
'imageSyncNotifications': 'IMAGE_SYNC_NOTIFICATIONS'
}
###############################################################################

View file

@ -16,6 +16,7 @@ from downloadutils import DownloadUtils as DU
import itemtypes
import plexdb_functions as plexdb
import kodidb_functions as kodidb
import artwork
import videonodes
import variables as v
@ -1453,7 +1454,6 @@ class LibrarySync(Thread):
elif state.RUN_LIB_SCAN == 'textures':
state.DB_SCAN = True
window('plex_dbScan', value="true")
import artwork
artwork.Artwork().fullTextureCacheSync()
window('plex_dbScan', clear=True)
state.DB_SCAN = False
@ -1517,8 +1517,6 @@ class LibrarySync(Thread):
last_time_sync = utils.unix_timestamp()
window('plex_dbScan', clear=True)
state.DB_SCAN = False
# Start the fanart download thread
self.fanartthread.start()
while not self.stopped():
# In the event the server goes offline
@ -1544,6 +1542,7 @@ class LibrarySync(Thread):
initial_sync_done = True
kodi_db_version_checked = True
last_sync = utils.unix_timestamp()
self.fanartthread.start()
else:
LOG.error('Initial start-up full sync unsuccessful')
xbmc.executebuiltin('InhibitIdleShutdown(false)')
@ -1587,6 +1586,8 @@ class LibrarySync(Thread):
if settings('FanartTV') == 'true':
self.sync_fanart()
LOG.info('Done initial sync on Kodi startup')
artwork.Artwork().cache_major_artwork()
self.fanartthread.start()
else:
LOG.info('Startup sync has not yet been successful')
window('plex_dbScan', clear=True)

View file

@ -4,12 +4,31 @@ from cPickle import dumps, loads
from xbmcgui import Window
from xbmc import log, LOGDEBUG
###############################################################################
WINDOW = Window(10000)
PREFIX = 'PLEX.%s: ' % __name__
###############################################################################
def try_encode(input_str, encoding='utf-8'):
"""
Will try to encode input_str (in unicode) to encoding. This possibly
fails with e.g. Android TV's Python, which does not accept arguments for
string.encode()
COPY to avoid importing utils on calling default.py
"""
if isinstance(input_str, str):
# already encoded
return input_str
try:
input_str = input_str.encode(encoding, "ignore")
except TypeError:
input_str = input_str.encode()
return input_str
def pickl_window(property, value=None, clear=False):
"""
Get or set window property - thread safe! For use with Pickle
@ -20,7 +39,7 @@ def pickl_window(property, value=None, clear=False):
elif value is not None:
WINDOW.setProperty(property, value)
else:
return WINDOW.getProperty(property)
return try_encode(WINDOW.getProperty(property))
def pickle_me(obj, window_var='plex_result'):

View file

@ -39,6 +39,8 @@ FORCE_RELOAD_SKIN = True
# Stemming from the PKC settings.xml
# Shall we show Kodi dialogs when synching?
SYNC_DIALOG = True
# Shall Kodi show dialogs for syncing/caching images? (e.g. images left to sync)
IMAGE_SYNC_NOTIFICATIONS = True
# Is synching of Plex music enabled?
ENABLE_MUSIC = True
# How often shall we sync?

View file

@ -22,7 +22,9 @@ LOG = getLogger("PLEX." + __name__)
@thread_methods(add_suspends=['SUSPEND_USER_CLIENT'])
class UserClient(Thread):
"""
Manage Plex users
"""
# Borg - multiple instances, shared state
__shared_state = {}
@ -32,100 +34,98 @@ class UserClient(Thread):
self.auth = True
self.retry = 0
self.currUser = None
self.currServer = None
self.currToken = None
self.HasAccess = True
self.AdditionalUser = []
self.user = None
self.has_access = True
self.userSettings = None
self.server = None
self.server_name = None
self.machine_identifier = None
self.token = None
self.ssl = None
self.sslcert = None
self.addon = xbmcaddon.Addon()
self.doUtils = DU()
self.do_utils = None
Thread.__init__(self)
def getUsername(self):
def get_server(self):
"""
Returns username as unicode
Get the current PMS' URL
"""
username = settings('username')
if not username:
LOG.debug("No username saved, trying to get Plex username")
username = settings('plexLogin')
if not username:
LOG.debug("Also no Plex username found")
return ""
return username
def getServer(self, prefix=True):
# Original host
self.servername = settings('plex_servername')
HTTPS = settings('https') == "true"
self.server_name = settings('plex_servername')
https = settings('https') == "true"
host = settings('ipaddress')
port = settings('port')
self.machineIdentifier = settings('plex_machineIdentifier')
server = host + ":" + port
self.machine_identifier = settings('plex_machineIdentifier')
if not host:
LOG.debug("No server information saved.")
return False
server = host + ":" + port
# If https is true
if prefix and HTTPS:
if https:
server = "https://%s" % server
# If https is false
elif prefix and not HTTPS:
else:
server = "http://%s" % server
# User entered IP; we need to get the machineIdentifier
if self.machineIdentifier == '' and prefix is True:
self.machineIdentifier = PF.GetMachineIdentifier(server)
if self.machineIdentifier is None:
self.machineIdentifier = ''
settings('plex_machineIdentifier', value=self.machineIdentifier)
if not self.machine_identifier:
self.machine_identifier = PF.GetMachineIdentifier(server)
if not self.machine_identifier:
self.machine_identifier = ''
settings('plex_machineIdentifier', value=self.machine_identifier)
LOG.debug('Returning active server: %s', server)
return server
def getSSLverify(self):
# Verify host certificate
@staticmethod
def get_ssl_verify():
"""
Do we need to verify the SSL certificate? Return None if that is the
case, else False
"""
return None if settings('sslverify') == 'true' else False
def getSSL(self):
# Client side certificate
@staticmethod
def get_ssl_certificate():
"""
Client side certificate
"""
return None if settings('sslcert') == 'None' \
else settings('sslcert')
def setUserPref(self):
def set_user_prefs(self):
"""
Load a user's profile picture
"""
LOG.debug('Setting user preferences')
# Only try to get user avatar if there is a token
if self.currToken:
url = PF.GetUserArtworkURL(self.currUser)
if self.token:
url = PF.GetUserArtworkURL(self.user)
if url:
window('PlexUserImage', value=url)
# Set resume point max
# url = "{server}/emby/System/Configuration?format=json"
# result = doUtils.downloadUrl(url)
def hasAccess(self):
@staticmethod
def check_access():
# Plex: always return True for now
return True
def loadCurrUser(self, username, userId, usertoken, authenticated=False):
def load_user(self, username, user_id, usertoken, authenticated=False):
"""
Load the current user's details for PKC
"""
LOG.debug('Loading current user')
doUtils = self.doUtils
self.currToken = usertoken
self.currServer = self.getServer()
self.ssl = self.getSSLverify()
self.sslcert = self.getSSL()
self.token = usertoken
self.server = self.get_server()
self.ssl = self.get_ssl_verify()
self.sslcert = self.get_ssl_certificate()
if authenticated is False:
if self.currServer is None:
if self.server is None:
return False
LOG.debug('Testing validity of current token')
res = PF.check_connection(self.currServer,
token=self.currToken,
res = PF.check_connection(self.server,
token=self.token,
verifySSL=self.ssl)
if res is False:
# PMS probably offline
@ -138,7 +138,7 @@ class UserClient(Thread):
return False
# Set to windows property
state.PLEX_USER_ID = userId or None
state.PLEX_USER_ID = user_id or None
state.PLEX_USERNAME = username
# This is the token for the current PMS (might also be '')
window('pms_token', value=usertoken)
@ -150,9 +150,9 @@ class UserClient(Thread):
window('plex_restricteduser', value=settings('plex_restricteduser'))
state.RESTRICTED_USER = True \
if settings('plex_restricteduser') == 'true' else False
window('pms_server', value=self.currServer)
window('plex_machineIdentifier', value=self.machineIdentifier)
window('plex_servername', value=self.servername)
window('pms_server', value=self.server)
window('plex_machineIdentifier', value=self.machine_identifier)
window('plex_servername', value=self.server_name)
window('plex_authenticated', value='true')
state.AUTHENTICATED = True
@ -166,19 +166,22 @@ class UserClient(Thread):
if settings('force_transcode_pix') == "1" else 'false')
# Start DownloadUtils session
doUtils.startSession(reset=True)
# self.getAdditionalUsers()
self.do_utils = DU()
self.do_utils.startSession(reset=True)
# Set user preferences in settings
self.currUser = username
self.setUserPref()
self.user = username
self.set_user_prefs()
# Writing values to settings file
settings('username', value=username)
settings('userid', value=userId)
settings('userid', value=user_id)
settings('accessToken', value=usertoken)
return True
def authenticate(self):
"""
Authenticate the current user
"""
LOG.debug('Authenticating user')
# Give attempts at entering password / selecting user
@ -198,7 +201,7 @@ class UserClient(Thread):
LOG.error("Error, no settings.xml found.")
self.auth = False
return False
server = self.getServer()
server = self.get_server()
# If there is no server we can connect to
if not server:
LOG.info("Missing server information.")
@ -213,10 +216,10 @@ class UserClient(Thread):
# Found a user in the settings, try to authenticate
if username and enforceLogin == 'false':
LOG.debug('Trying to authenticate with old settings')
answ = self.loadCurrUser(username,
userId,
usertoken,
authenticated=False)
answ = self.load_user(username,
userId,
usertoken,
authenticated=False)
if answ is True:
# SUCCESS: loaded a user from the settings
return True
@ -248,7 +251,7 @@ class UserClient(Thread):
userId = ''
usertoken = ''
if self.loadCurrUser(username, userId, usertoken, authenticated=False):
if self.load_user(username, userId, usertoken, authenticated=False):
# SUCCESS: loaded a user from the settings
return True
# Something went wrong, try again
@ -256,9 +259,12 @@ class UserClient(Thread):
self.retry += 1
return False
def resetClient(self):
def reset_client(self):
"""
Reset all user settings
"""
LOG.debug("Reset UserClient authentication.")
self.doUtils.stopSession()
self.do_utils.stopSession()
window('plex_authenticated', clear=True)
state.AUTHENTICATED = False
@ -279,13 +285,16 @@ class UserClient(Thread):
settings('userid', value='')
settings('accessToken', value='')
self.currToken = None
self.token = None
self.auth = True
self.currUser = None
self.user = None
self.retry = 0
def run(self):
"""
Do the work
"""
LOG.info("----===## Starting UserClient ##===----")
stopped = self.stopped
suspended = self.suspended
@ -299,19 +308,14 @@ class UserClient(Thread):
sleep(500)
continue
# Verify the connection status to server
elif state.PMS_STATUS == "restricted":
# Parental control is restricting access
self.HasAccess = False
elif state.PMS_STATUS == "401":
# Unauthorized access, revoke token
state.PMS_STATUS = 'Auth'
window('plex_serverStatus', value='Auth')
self.resetClient()
self.reset_client()
sleep(3000)
if self.auth and (self.currUser is None):
if self.auth and (self.user is None):
# Try to authenticate user
if not state.PMS_STATUS or state.PMS_STATUS == "Auth":
# Set auth flag because we no longer need
@ -320,16 +324,16 @@ class UserClient(Thread):
if self.authenticate():
# Successfully authenticated and loaded a user
LOG.info("Successfully authenticated!")
LOG.info("Current user: %s", self.currUser)
LOG.info("Current user: %s", self.user)
LOG.info("Current userId: %s", state.PLEX_USER_ID)
self.retry = 0
state.SUSPEND_LIBRARY_THREAD = False
window('plex_serverStatus', clear=True)
state.PMS_STATUS = False
if not self.auth and (self.currUser is None):
if not self.auth and (self.user is None):
# Loop if no server found
server = self.getServer()
server = self.get_server()
# The status Stop is for when user cancelled password dialog.
# Or retried too many times

View file

@ -325,6 +325,13 @@ KODI_TO_PLEX_ARTWORK = {
'fanart': 'art'
}
KODI_TO_PLEX_ARTWORK_EPISODE = {
'thumb': 'thumb',
'poster': 'grandparentThumb',
'banner': 'banner',
'fanart': 'art'
}
# Might be implemented in the future: 'icon', 'landscape' (16:9)
ALL_KODI_ARTWORK = (
'thumb',

View file

@ -125,6 +125,8 @@
<setting id="enableTextureCache" label="30512" type="bool" default="true" /> <!-- Force Artwork Caching -->
<setting id="FanartTV" label="30539" type="bool" default="false" /><!-- Download additional art from FanArtTV -->
<setting label="39222" type="action" action="RunPlugin(plugin://plugin.video.plexkodiconnect/?mode=fanart)" option="close" visible="eq(-1,true)" subsetting="true" /> <!-- Look for missing fanart on FanartTV now -->
<setting id="imageSyncNotifications" label="30008" type="bool" default="true" /><!-- Enable notifications for image caching -->
<setting id="imageSyncDuringPlayback" label="30009" type="bool" default="true" /><!-- Enable image caching during Kodi playback (restart Kodi!) -->
<setting label="39020" type="action" action="RunPlugin(plugin://plugin.video.plexkodiconnect/?mode=texturecache)" option="close" /> <!-- Cache all images to Kodi texture cache now -->
</category>
<!--

View file

@ -135,7 +135,7 @@ class Service():
if window('plex_online') == "true":
# Plex server is online
# Verify if user is set and has access to the server
if (self.user.currUser is not None) and self.user.HasAccess:
if (self.user.user is not None) and self.user.has_access:
if not self.kodimonitor_running:
# Start up events
self.warn_auth = True
@ -145,7 +145,7 @@ class Service():
dialog('notification',
lang(29999),
"%s %s" % (lang(33000),
self.user.currUser),
self.user.user),
icon='{plex}',
time=2000,
sound=False)
@ -178,7 +178,7 @@ class Service():
self.image_cache_thread_running = True
self.image_cache_thread.start()
else:
if (self.user.currUser is None) and self.warn_auth:
if (self.user.user is None) and self.warn_auth:
# Alert user is not authenticated and suppress future
# warning
self.warn_auth = False
@ -187,9 +187,9 @@ class Service():
# User access is restricted.
# Keep verifying until access is granted
# unless server goes offline or Kodi is shut down.
while self.user.HasAccess is False:
while self.user.has_access is False:
# Verify access with an API call
self.user.hasAccess()
self.user.check_access()
if window('plex_online') != "true":
# Server went offline
@ -202,7 +202,7 @@ class Service():
# Wait until Plex server is online
# or Kodi is shut down.
while not self.__stop_PKC():
server = self.user.getServer()
server = self.user.get_server()
if server is False:
# No server info set in add-on settings
pass