PlexKodiConnect/resources/lib/entrypoint.py

1018 lines
37 KiB
Python
Raw Normal View History

2015-12-25 07:07:00 +11:00
# -*- coding: utf-8 -*-
2016-02-20 06:03:06 +11:00
###############################################################################
2016-08-30 23:51:11 +10:00
import logging
2017-01-25 05:59:38 +11:00
from os import path as os_path
from sys import argv
from urllib import urlencode
2015-12-25 07:07:00 +11:00
import xbmcplugin
2017-01-25 05:59:38 +11:00
from xbmc import sleep, Player, executebuiltin, getCondVisibility, \
translatePath
from xbmcgui import ListItem
2015-12-25 07:07:00 +11:00
2017-01-25 05:59:38 +11:00
from utils import window, settings, language as lang, dialog, tryDecode,\
tryEncode, CatchExceptions, JSONRPC
2015-12-25 07:07:00 +11:00
import downloadutils
import playbackutils as pbutils
2017-01-25 05:59:38 +11:00
from PlexFunctions import GetPlexMetadata, GetPlexSectionResults, \
GetMachineIdentifier
from PlexAPI import API
2017-01-03 02:42:07 +11:00
from PKC_listitem import convert_PKC_to_listitem
2017-01-10 05:56:57 +11:00
from playqueue import Playqueue
import variables as v
2016-01-02 00:40:40 +11:00
2016-02-20 06:03:06 +11:00
###############################################################################
2016-08-30 23:51:11 +10:00
log = logging.getLogger("PLEX."+__name__)
2017-01-25 06:04:53 +11:00
try:
HANDLE = int(argv[1])
ARGV_0 = argv[0]
except IndexError:
pass
2016-08-30 23:51:11 +10:00
###############################################################################
2016-01-30 06:07:21 +11:00
def chooseServer():
"""
2016-05-30 00:52:00 +10:00
Lets user choose from list of PMS
"""
2016-08-30 23:51:11 +10:00
log.info("Choosing PMS server requested, starting")
import initialsetup
2016-05-25 04:43:52 +10:00
setup = initialsetup.InitialSetup()
2016-05-30 00:52:00 +10:00
server = setup.PickPMS(showDialog=True)
2016-05-25 04:43:52 +10:00
if server is None:
2016-08-30 23:51:11 +10:00
log.error('We did not connect to a new PMS, aborting')
window('suspend_Userclient', clear=True)
window('suspend_LibraryThread', clear=True)
2016-05-25 04:43:52 +10:00
return
2016-08-30 23:51:11 +10:00
log.info("User chose server %s" % server['name'])
2016-05-25 04:43:52 +10:00
setup.WritePMStoSettings(server)
if not __LogOut():
2016-05-30 00:52:00 +10:00
return
2016-08-30 23:51:11 +10:00
from utils import deletePlaylists, deleteNodes
2016-05-30 01:17:33 +10:00
# First remove playlists
2016-08-30 23:51:11 +10:00
deletePlaylists()
2016-05-30 01:17:33 +10:00
# Remove video nodes
2016-08-30 23:51:11 +10:00
deleteNodes()
2016-05-30 01:17:33 +10:00
2016-05-30 00:52:00 +10:00
# Log in again
__LogIn()
2016-08-30 23:51:11 +10:00
log.info("Choosing new PMS complete")
2016-05-30 00:52:00 +10:00
# '<PMS> connected'
2017-01-25 05:59:38 +11:00
dialog('notification',
lang(29999),
'%s %s' % (server['name'], lang(39220)),
icon='{plex}',
time=3000,
sound=False)
2016-05-30 00:52:00 +10:00
def togglePlexTV():
2016-08-30 23:51:11 +10:00
if settings('plexToken'):
log.info('Reseting plex.tv credentials in settings')
settings('plexLogin', value="")
settings('plexToken', value=""),
settings('plexid', value="")
settings('plexHomeSize', value="1")
settings('plexAvatar', value="")
settings('plex_status', value="Not logged in to plex.tv")
window('plex_token', clear=True)
window('plex_username', clear=True)
2016-05-30 00:52:00 +10:00
else:
2016-08-30 23:51:11 +10:00
log.info('Login to plex.tv')
2016-05-30 00:52:00 +10:00
import initialsetup
initialsetup.InitialSetup().PlexTVSignIn()
2017-01-25 05:59:38 +11:00
dialog('notification',
lang(29999),
lang(39221),
icon='{plex}',
time=3000,
sound=False)
2016-03-04 23:34:30 +11:00
2017-01-03 02:42:07 +11:00
def Plex_Node(url, viewOffset, plex_type, playdirectly=False):
"""
Called only for a SINGLE element for Plex.tv watch later
Always to return with a "setResolvedUrl"
"""
2017-01-03 01:41:38 +11:00
log.info('Plex_Node called with url: %s, viewOffset: %s'
% (url, viewOffset))
# Plex redirect, e.g. watch later. Need to get actual URLs
2017-01-03 02:42:07 +11:00
xml = downloadutils.DownloadUtils().downloadUrl(url)
try:
xml[0].attrib
except:
log.error('Could not download PMS metadata')
return
2016-06-20 02:53:45 +10:00
if viewOffset != '0':
try:
viewOffset = int(v.PLEX_TO_KODI_TIMEFACTOR *
2016-06-20 02:53:45 +10:00
float(viewOffset))
except:
pass
else:
2016-08-30 23:51:11 +10:00
window('plex_customplaylist.seektime', value=str(viewOffset))
log.info('Set resume point to %s' % str(viewOffset))
typus = v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[plex_type]
2017-01-10 05:56:57 +11:00
playqueue = Playqueue().get_playqueue_from_type(typus)
result = pbutils.PlaybackUtils(xml, playqueue).play(
2017-01-03 02:42:07 +11:00
None,
kodi_id='plexnode',
plex_lib_UUID=xml.attrib.get('librarySectionUUID'))
if result.listitem:
listitem = convert_PKC_to_listitem(result.listitem)
else:
return
if playdirectly:
2017-01-25 05:59:38 +11:00
Player().play(listitem.getfilename(), listitem)
2017-01-03 02:42:07 +11:00
else:
2017-01-25 05:59:38 +11:00
xbmcplugin.setResolvedUrl(HANDLE, True, listitem)
2015-12-25 07:07:00 +11:00
##### DO RESET AUTH #####
def resetAuth():
# User tried login and failed too many times
2017-01-25 05:59:38 +11:00
resp = dialog('yesno', heading="{plex}", line1=lang(39206))
2015-12-25 07:07:00 +11:00
if resp == 1:
2016-08-30 23:51:11 +10:00
log.info("Reset login attempts.")
window('plex_serverStatus', value="Auth")
2015-12-25 07:07:00 +11:00
else:
2017-01-25 05:59:38 +11:00
executebuiltin('Addon.OpenSettings(plugin.video.plexkodiconnect)')
2016-08-30 23:51:11 +10:00
2015-12-25 07:07:00 +11:00
def addDirectoryItem(label, path, folder=True):
2017-01-25 05:59:38 +11:00
li = ListItem(label, path=path)
li.setThumbnailImage("special://home/addons/plugin.video.plexkodiconnect/icon.png")
li.setArt({"fanart":"special://home/addons/plugin.video.plexkodiconnect/fanart.jpg"})
li.setArt({"landscape":"special://home/addons/plugin.video.plexkodiconnect/fanart.jpg"})
2017-01-25 05:59:38 +11:00
xbmcplugin.addDirectoryItem(handle=HANDLE, url=path, listitem=li, isFolder=folder)
2015-12-25 07:07:00 +11:00
2016-08-30 23:51:11 +10:00
2015-12-25 07:07:00 +11:00
def doMainListing():
2017-01-25 05:59:38 +11:00
xbmcplugin.setContent(HANDLE, 'files')
2015-12-25 07:07:00 +11:00
# Get emby nodes from the window props
2016-08-30 23:51:11 +10:00
plexprops = window('Plex.nodes.total')
2016-05-31 16:06:42 +10:00
if plexprops:
totalnodes = int(plexprops)
2015-12-25 07:07:00 +11:00
for i in range(totalnodes):
2016-08-30 23:51:11 +10:00
path = window('Plex.nodes.%s.index' % i)
2015-12-25 07:07:00 +11:00
if not path:
2016-08-30 23:51:11 +10:00
path = window('Plex.nodes.%s.content' % i)
label = window('Plex.nodes.%s.title' % i)
node_type = window('Plex.nodes.%s.type' % i)
#because we do not use seperate entrypoints for each content type, we need to figure out which items to show in each listing.
2016-01-22 21:10:42 +11:00
#for now we just only show picture nodes in the picture library video nodes in the video library and all nodes in any other window
2017-01-25 05:59:38 +11:00
if path and getCondVisibility("Window.IsActive(Pictures)") and node_type == "photos":
2015-12-25 07:07:00 +11:00
addDirectoryItem(label, path)
2017-01-25 05:59:38 +11:00
elif path and getCondVisibility("Window.IsActive(VideoLibrary)") and node_type != "photos":
2016-01-19 06:48:44 +11:00
addDirectoryItem(label, path)
2017-01-25 05:59:38 +11:00
elif path and not getCondVisibility("Window.IsActive(VideoLibrary) | Window.IsActive(Pictures) | Window.IsActive(MusicLibrary)"):
2015-12-25 07:07:00 +11:00
addDirectoryItem(label, path)
2016-04-17 21:36:41 +10:00
# Plex Watch later
2016-08-30 23:51:11 +10:00
addDirectoryItem(lang(39211),
2016-04-17 21:36:41 +10:00
"plugin://plugin.video.plexkodiconnect/?mode=watchlater")
2016-03-11 02:04:01 +11:00
# Plex user switch
2016-08-30 23:51:11 +10:00
addDirectoryItem(lang(39200) + window('plex_username'),
2016-03-11 02:04:01 +11:00
"plugin://plugin.video.plexkodiconnect/"
"?mode=switchuser")
2016-01-25 20:36:24 +11:00
#experimental live tv nodes
# addDirectoryItem("Live Tv Channels (experimental)", "plugin://plugin.video.plexkodiconnect/?mode=browsecontent&type=tvchannels&folderid=root")
# addDirectoryItem("Live Tv Recordings (experimental)", "plugin://plugin.video.plexkodiconnect/?mode=browsecontent&type=recordings&folderid=root")
2015-12-25 07:07:00 +11:00
# some extra entries for settings and stuff. TODO --> localize the labels
2016-08-30 23:51:11 +10:00
addDirectoryItem(lang(39201), "plugin://plugin.video.plexkodiconnect/?mode=settings")
# addDirectoryItem("Add user to session", "plugin://plugin.video.plexkodiconnect/?mode=adduser")
2016-08-30 23:51:11 +10:00
addDirectoryItem(lang(39203), "plugin://plugin.video.plexkodiconnect/?mode=refreshplaylist")
addDirectoryItem(lang(39204), "plugin://plugin.video.plexkodiconnect/?mode=manualsync")
2017-01-25 05:59:38 +11:00
xbmcplugin.endOfDirectory(HANDLE)
2015-12-25 07:07:00 +11:00
2016-02-29 16:20:59 +11:00
##### Generate a new deviceId
def resetDeviceId():
2016-08-30 23:51:11 +10:00
deviceId_old = window('plex_client_Id')
2017-01-25 02:53:50 +11:00
from clientinfo import getDeviceId
2016-02-29 16:20:59 +11:00
try:
2017-01-25 02:53:50 +11:00
deviceId = getDeviceId(reset=True)
2016-02-29 16:20:59 +11:00
except Exception as e:
2016-08-30 23:51:11 +10:00
log.error("Failed to generate a new device Id: %s" % e)
2017-01-25 05:59:38 +11:00
dialog('ok', lang(29999), lang(33032))
2016-02-29 16:20:59 +11:00
else:
2016-08-30 23:51:11 +10:00
log.info("Successfully removed old deviceId: %s New deviceId: %s"
% (deviceId_old, deviceId))
# "Kodi will now restart to apply the changes"
2017-01-25 05:59:38 +11:00
dialog('ok', lang(29999), lang(33033))
executebuiltin('RestartApp')
2016-01-25 20:36:24 +11:00
def switchPlexUser():
"""
Signs out currently logged in user (if applicable). Triggers sign-in of a
new user
"""
# Guess these user avatars are a future feature. Skipping for now
# Delete any userimages. Since there's always only 1 user: position = 0
# position = 0
2016-08-30 23:51:11 +10:00
# window('EmbyAdditionalUserImage.%s' % position, clear=True)
log.info("Plex home user switch requested")
if not __LogOut():
2016-05-30 00:52:00 +10:00
return
2016-03-10 01:53:46 +11:00
2016-05-30 00:52:00 +10:00
# First remove playlists of old user
2016-08-30 23:51:11 +10:00
from utils import deletePlaylists, deleteNodes
deletePlaylists()
# Remove video nodes
2016-08-30 23:51:11 +10:00
deleteNodes()
2016-05-30 00:52:00 +10:00
__LogIn()
2016-01-25 20:36:24 +11:00
##### REFRESH EMBY PLAYLISTS #####
def refreshPlaylist():
2016-08-30 23:51:11 +10:00
log.info('Requesting playlist/nodes refresh')
window('plex_runLibScan', value="views")
2016-01-22 21:10:42 +11:00
#### SHOW SUBFOLDERS FOR NODE #####
def GetSubFolders(nodeindex):
nodetypes = ["",".recent",".recentepisodes",".inprogress",".inprogressepisodes",".unwatched",".nextepisodes",".sets",".genres",".random",".recommended"]
for node in nodetypes:
2016-08-30 23:51:11 +10:00
title = window('Plex.nodes.%s%s.title' %(nodeindex,node))
2016-01-22 21:10:42 +11:00
if title:
2016-08-30 23:51:11 +10:00
path = window('Plex.nodes.%s%s.content' %(nodeindex,node))
2016-01-22 21:10:42 +11:00
addDirectoryItem(title, path)
2017-01-25 05:59:38 +11:00
xbmcplugin.endOfDirectory(HANDLE)
2015-12-25 07:07:00 +11:00
##### LISTITEM SETUP FOR VIDEONODES #####
def createListItem(item, appendShowTitle=False, appendSxxExx=False):
2015-12-25 07:07:00 +11:00
title = item['title']
2017-01-25 05:59:38 +11:00
li = ListItem(title)
2015-12-25 07:07:00 +11:00
li.setProperty('IsPlayable', "true")
metadata = {
2015-12-25 07:07:00 +11:00
'duration': str(item['runtime']/60),
'Plot': item['plot'],
'Playcount': item['playcount']
}
if "episode" in item:
episode = item['episode']
metadata['Episode'] = episode
if "season" in item:
season = item['season']
metadata['Season'] = season
if season and episode:
li.setProperty('episodeno', "s%.2de%.2d" % (season, episode))
if appendSxxExx is True:
title = "S%.2dE%.2d - %s" % (season, episode, title)
2015-12-25 07:07:00 +11:00
if "firstaired" in item:
metadata['Premiered'] = item['firstaired']
if "showtitle" in item:
metadata['TVshowTitle'] = item['showtitle']
if appendShowTitle is True:
title = item['showtitle'] + ' - ' + title
2015-12-25 07:07:00 +11:00
if "rating" in item:
metadata['Rating'] = str(round(float(item['rating']),1))
if "director" in item:
metadata['Director'] = " / ".join(item['director'])
if "writer" in item:
metadata['Writer'] = " / ".join(item['writer'])
if "cast" in item:
cast = []
castandrole = []
for person in item['cast']:
name = person['name']
cast.append(name)
castandrole.append((name, person['role']))
metadata['Cast'] = cast
metadata['CastAndRole'] = castandrole
metadata['Title'] = title
li.setLabel(title)
2015-12-25 07:07:00 +11:00
li.setInfo(type="Video", infoLabels=metadata)
li.setProperty('resumetime', str(item['resume']['position']))
li.setProperty('totaltime', str(item['resume']['total']))
li.setArt(item['art'])
li.setThumbnailImage(item['art'].get('thumb',''))
2017-01-03 00:07:24 +11:00
li.setArt({'icon': 'DefaultTVShows.png'})
2015-12-25 07:07:00 +11:00
li.setProperty('dbid', str(item['episodeid']))
li.setProperty('fanart_image', item['art'].get('tvshow.fanart',''))
for key, value in item['streamdetails'].iteritems():
for stream in value:
li.addStreamInfo(key, stream)
return li
##### GET NEXTUP EPISODES FOR TAGNAME #####
def getNextUpEpisodes(tagname, limit):
count = 0
# if the addon is called with nextup parameter,
# we return the nextepisodes list of the given tagname
2017-01-25 05:59:38 +11:00
xbmcplugin.setContent(HANDLE, 'episodes')
2015-12-25 07:07:00 +11:00
# First we get a list of all the TV shows - filtered by tag
2017-01-25 05:59:38 +11:00
params = {
'sort': {'order': "descending", 'method': "lastplayed"},
'filter': {
'and': [
{'operator': "true", 'field': "inprogress", 'value': ""},
{'operator': "is", 'field': "tag", 'value': "%s" % tagname}
]},
'properties': ['title', 'studio', 'mpaa', 'file', 'art']
2015-12-25 07:07:00 +11:00
}
2017-01-25 05:59:38 +11:00
result = JSONRPC('VideoLibrary.GetTVShows').execute(params)
2015-12-25 07:07:00 +11:00
# If we found any, find the oldest unwatched show for each one.
try:
items = result['result']['tvshows']
except (KeyError, TypeError):
pass
else:
for item in items:
2016-08-30 23:51:11 +10:00
if settings('ignoreSpecialsNextEpisodes') == "true":
2017-01-25 05:59:38 +11:00
params = {
'tvshowid': item['tvshowid'],
'sort': {'method': "episode"},
'filter': {
'and': [
{'operator': "lessthan",
'field': "playcount",
'value': "1"},
{'operator': "greaterthan",
'field': "season",
'value': "0"}]},
'properties': [
"title", "playcount", "season", "episode", "showtitle",
"plot", "file", "rating", "resume", "tvshowid", "art",
"streamdetails", "firstaired", "runtime", "writer",
"dateadded", "lastplayed"
],
'limits': {"end": 1}
2015-12-25 07:07:00 +11:00
}
else:
2017-01-25 05:59:38 +11:00
params = {
'tvshowid': item['tvshowid'],
'sort': {'method': "episode"},
'filter': {
'operator': "lessthan",
'field': "playcount",
'value': "1"},
'properties': [
"title", "playcount", "season", "episode", "showtitle",
"plot", "file", "rating", "resume", "tvshowid", "art",
"streamdetails", "firstaired", "runtime", "writer",
"dateadded", "lastplayed"
],
'limits': {"end": 1}
2015-12-25 07:07:00 +11:00
}
2017-01-25 05:59:38 +11:00
result = JSONRPC('VideoLibrary.GetEpisodes').execute(params)
2015-12-25 07:07:00 +11:00
try:
episodes = result['result']['episodes']
except (KeyError, TypeError):
pass
else:
for episode in episodes:
li = createListItem(episode)
2017-01-25 05:59:38 +11:00
xbmcplugin.addDirectoryItem(handle=HANDLE,
url=episode['file'],
listitem=li)
2015-12-25 07:07:00 +11:00
count += 1
if count == limit:
break
2017-01-25 05:59:38 +11:00
xbmcplugin.endOfDirectory(handle=HANDLE)
2015-12-25 07:07:00 +11:00
2017-01-25 05:59:38 +11:00
##### GET INPROGRESS EPISODES FOR TAGNAME #####
2015-12-25 07:07:00 +11:00
def getInProgressEpisodes(tagname, limit):
count = 0
# if the addon is called with inprogressepisodes parameter,
# we return the inprogressepisodes list of the given tagname
2017-01-25 05:59:38 +11:00
xbmcplugin.setContent(HANDLE, 'episodes')
2015-12-25 07:07:00 +11:00
# First we get a list of all the in-progress TV shows - filtered by tag
2017-01-25 05:59:38 +11:00
params = {
'sort': {'order': "descending", 'method': "lastplayed"},
'filter': {
'and': [
{'operator': "true", 'field': "inprogress", 'value': ""},
{'operator': "is", 'field': "tag", 'value': "%s" % tagname}
]},
'properties': ['title', 'studio', 'mpaa', 'file', 'art']
2015-12-25 07:07:00 +11:00
}
2017-01-25 05:59:38 +11:00
result = JSONRPC('VideoLibrary.GetTVShows').execute(params)
2015-12-25 07:07:00 +11:00
# If we found any, find the oldest unwatched show for each one.
try:
items = result['result']['tvshows']
except (KeyError, TypeError):
pass
else:
for item in items:
2017-01-25 05:59:38 +11:00
params = {
'tvshowid': item['tvshowid'],
'sort': {'method': "episode"},
'filter': {
'operator': "true",
'field': "inprogress",
'value': ""},
'properties': ["title", "playcount", "season", "episode",
"showtitle", "plot", "file", "rating", "resume",
"tvshowid", "art", "cast", "streamdetails", "firstaired",
"runtime", "writer", "dateadded", "lastplayed"]
2015-12-25 07:07:00 +11:00
}
2017-01-25 05:59:38 +11:00
result = JSONRPC('VideoLibrary.GetEpisodes').execute(params)
2015-12-25 07:07:00 +11:00
try:
episodes = result['result']['episodes']
except (KeyError, TypeError):
pass
else:
for episode in episodes:
li = createListItem(episode)
2017-01-25 05:59:38 +11:00
xbmcplugin.addDirectoryItem(handle=HANDLE,
url=episode['file'],
listitem=li)
2015-12-25 07:07:00 +11:00
count += 1
if count == limit:
break
2017-01-25 05:59:38 +11:00
xbmcplugin.endOfDirectory(handle=HANDLE)
2015-12-25 07:07:00 +11:00
##### GET RECENT EPISODES FOR TAGNAME #####
2016-03-16 00:19:56 +11:00
# def getRecentEpisodes(tagname, limit):
def getRecentEpisodes(viewid, mediatype, tagname, limit):
2015-12-25 07:07:00 +11:00
count = 0
# if the addon is called with recentepisodes parameter,
# we return the recentepisodes list of the given tagname
2017-01-25 05:59:38 +11:00
xbmcplugin.setContent(HANDLE, 'episodes')
2016-08-30 23:51:11 +10:00
appendShowTitle = settings('RecentTvAppendShow') == 'true'
appendSxxExx = settings('RecentTvAppendSeason') == 'true'
2015-12-25 07:07:00 +11:00
# First we get a list of all the TV shows - filtered by tag
2017-01-25 05:59:38 +11:00
params = {
'sort': {'order': "descending", 'method': "dateadded"},
'filter': {'operator': "is", 'field': "tag", 'value': "%s" % tagname},
2015-12-25 07:07:00 +11:00
}
2017-01-25 05:59:38 +11:00
result = JSONRPC('VideoLibrary.GetTVShows').execute(params)
2015-12-25 07:07:00 +11:00
# If we found any, find the oldest unwatched show for each one.
try:
2016-03-16 00:19:56 +11:00
items = result['result'][mediatype]
except (KeyError, TypeError):
# No items, empty folder
2017-01-25 05:59:38 +11:00
xbmcplugin.endOfDirectory(handle=HANDLE)
2016-03-16 00:19:56 +11:00
return
allshowsIds = set()
for item in items:
allshowsIds.add(item['tvshowid'])
2017-01-25 05:59:38 +11:00
params = {
'sort': {'order': "descending", 'method': "dateadded"},
'properties': ["title", "playcount", "season", "episode", "showtitle",
"plot", "file", "rating", "resume", "tvshowid", "art",
"streamdetails", "firstaired", "runtime", "cast", "writer",
"dateadded", "lastplayed"],
"limits": {"end": limit}
2016-03-16 00:19:56 +11:00
}
2016-08-30 23:51:11 +10:00
if settings('TVShowWatched') == 'false':
2017-01-25 05:59:38 +11:00
params['filter'] = {
'operator': "lessthan",
'field': "playcount",
'value': "1"
}
2017-01-25 05:59:38 +11:00
result = JSONRPC('VideoLibrary.GetEpisodes').execute(params)
2016-03-16 00:19:56 +11:00
try:
episodes = result['result']['episodes']
2015-12-25 07:07:00 +11:00
except (KeyError, TypeError):
pass
else:
2016-03-16 00:19:56 +11:00
for episode in episodes:
if episode['tvshowid'] in allshowsIds:
li = createListItem(episode,
appendShowTitle=appendShowTitle,
appendSxxExx=appendSxxExx)
2016-03-16 00:19:56 +11:00
xbmcplugin.addDirectoryItem(
2017-01-25 05:59:38 +11:00
handle=HANDLE,
2016-03-16 00:19:56 +11:00
url=episode['file'],
listitem=li)
count += 1
2015-12-25 07:07:00 +11:00
2016-03-16 00:19:56 +11:00
if count == limit:
break
2015-12-25 07:07:00 +11:00
2017-01-25 05:59:38 +11:00
xbmcplugin.endOfDirectory(handle=HANDLE)
2015-12-25 07:07:00 +11:00
def getVideoFiles(plexId, params):
"""
GET VIDEO EXTRAS FOR LISTITEM
returns the video files for the item as plugin listing, can be used for
browsing the actual files or videoextras etc.
"""
if plexId is None:
filename = params.get('filename')
if filename is not None:
filename = filename[0]
import re
regex = re.compile(r'''library/metadata/(\d+)''')
filename = regex.findall(filename)
try:
plexId = filename[0]
except IndexError:
pass
if plexId is None:
2016-08-30 23:51:11 +10:00
log.info('No Plex ID found, abort getting Extras')
2017-01-25 05:59:38 +11:00
return xbmcplugin.endOfDirectory(HANDLE)
2017-01-25 05:59:38 +11:00
item = GetPlexMetadata(plexId)
try:
path = item[0][0][0].attrib['file']
except:
2016-08-30 23:51:11 +10:00
log.error('Could not get file path for item %s' % plexId)
2017-01-25 05:59:38 +11:00
return xbmcplugin.endOfDirectory(HANDLE)
# Assign network protocol
if path.startswith('\\\\'):
path = path.replace('\\\\', 'smb://')
path = path.replace('\\', '/')
# Plex returns Windows paths as e.g. 'c:\slfkjelf\slfje\file.mkv'
elif '\\' in path:
path = path.replace('\\', '\\\\')
# Directory only, get rid of filename (!! exists() needs / or \ at end)
2017-01-25 05:59:38 +11:00
path = path.replace(os_path.basename(path), '')
# Only proceed if we can access this folder
2017-01-25 05:59:38 +11:00
import xbmcvfs
if xbmcvfs.exists(path):
# Careful, returns encoded strings!
dirs, files = xbmcvfs.listdir(path)
for file in files:
2016-08-30 23:51:11 +10:00
file = path + tryDecode(file)
2017-01-25 05:59:38 +11:00
li = ListItem(file, path=file)
xbmcplugin.addDirectoryItem(handle=HANDLE,
2016-08-30 23:51:11 +10:00
url=tryEncode(file),
listitem=li)
for dir in dirs:
2016-08-30 23:51:11 +10:00
dir = path + tryDecode(dir)
2017-01-25 05:59:38 +11:00
li = ListItem(dir, path=dir)
xbmcplugin.addDirectoryItem(handle=HANDLE,
2016-08-30 23:51:11 +10:00
url=tryEncode(dir),
listitem=li,
isFolder=True)
else:
2016-08-30 23:51:11 +10:00
log.warn('Kodi cannot access folder %s' % path)
2017-01-25 05:59:38 +11:00
xbmcplugin.endOfDirectory(HANDLE)
2016-08-30 23:51:11 +10:00
@CatchExceptions(warnuser=False)
def getExtraFanArt(plexid, plexPath):
"""
Get extrafanart for listitem
will be called by skinhelper script to get the extrafanart
for tvshows we get the plexid just from the path
"""
2017-01-25 05:59:38 +11:00
import xbmcvfs
2016-08-30 23:51:11 +10:00
log.debug('Called with plexid: %s, plexPath: %s' % (plexid, plexPath))
if not plexid:
if "plugin.video.plexkodiconnect" in plexPath:
plexid = plexPath.split("/")[-2]
if not plexid:
2016-08-30 23:51:11 +10:00
log.error('Could not get a plexid, aborting')
2017-01-25 05:59:38 +11:00
return xbmcplugin.endOfDirectory(HANDLE)
2016-07-23 00:55:57 +10:00
# We need to store the images locally for this to work
# because of the caching system in xbmc
2017-01-25 05:59:38 +11:00
fanartDir = tryDecode(translatePath(
2016-07-23 00:55:57 +10:00
"special://thumbnails/plex/%s/" % plexid))
if not xbmcvfs.exists(fanartDir):
# Download the images to the cache directory
2016-08-30 23:51:11 +10:00
xbmcvfs.mkdirs(tryEncode(fanartDir))
2017-01-25 05:59:38 +11:00
xml = GetPlexMetadata(plexid)
2016-07-23 00:55:57 +10:00
if xml is None:
2016-08-30 23:51:11 +10:00
log.error('Could not download metadata for %s' % plexid)
2017-01-25 05:59:38 +11:00
return xbmcplugin.endOfDirectory(HANDLE)
2017-01-25 05:59:38 +11:00
api = API(xml[0])
backdrops = api.getAllArtwork()['Backdrop']
2016-07-23 00:55:57 +10:00
for count, backdrop in enumerate(backdrops):
# Same ordering as in artwork
2017-01-25 05:59:38 +11:00
if os_path.supports_unicode_filenames:
fanartFile = os_path.join(fanartDir,
2016-07-23 00:55:57 +10:00
"fanart%.3d.jpg" % count)
else:
2017-01-25 05:59:38 +11:00
fanartFile = os_path.join(
2016-08-30 23:51:11 +10:00
tryEncode(fanartDir),
tryEncode("fanart%.3d.jpg" % count))
2017-01-25 05:59:38 +11:00
li = ListItem("%.3d" % count, path=fanartFile)
2016-07-23 00:55:57 +10:00
xbmcplugin.addDirectoryItem(
2017-01-25 05:59:38 +11:00
handle=HANDLE,
2016-07-23 00:55:57 +10:00
url=fanartFile,
listitem=li)
xbmcvfs.copy(backdrop, fanartFile)
else:
2016-08-30 23:51:11 +10:00
log.info("Found cached backdrop.")
2016-07-23 00:55:57 +10:00
# Use existing cached images
dirs, files = xbmcvfs.listdir(fanartDir)
for file in files:
2017-01-25 05:59:38 +11:00
fanartFile = os_path.join(fanartDir, tryDecode(file))
li = ListItem(file, path=fanartFile)
xbmcplugin.addDirectoryItem(handle=HANDLE,
2016-07-23 00:55:57 +10:00
url=fanartFile,
listitem=li)
2017-01-25 05:59:38 +11:00
xbmcplugin.endOfDirectory(HANDLE)
def RunLibScan(mode):
2016-08-30 23:51:11 +10:00
if window('plex_online') != "true":
# Server is not online, do not run the sync
2017-01-25 05:59:38 +11:00
dialog('ok', lang(29999), lang(39205))
else:
2016-08-30 23:51:11 +10:00
window('plex_runLibScan', value='full')
2016-03-15 03:47:05 +11:00
2016-06-05 02:48:22 +10:00
def BrowsePlexContent(viewid, mediatype="", folderid=""):
2016-03-15 03:47:05 +11:00
"""
2016-06-05 02:48:22 +10:00
Browse Plex Photos:
2016-03-15 03:47:05 +11:00
viewid: PMS name of the library
2016-06-05 02:48:22 +10:00
mediatype: mediatype, 'photos'
nodetype: e.g. 'ondeck' (TBD!!)
2016-03-15 03:47:05 +11:00
"""
2016-08-30 23:51:11 +10:00
log.debug("BrowsePlexContent called with viewid: %s, mediatype: "
"%s, folderid: %s" % (viewid, mediatype, folderid))
2016-03-15 03:47:05 +11:00
2016-06-05 02:48:22 +10:00
if not folderid:
2016-06-13 01:22:22 +10:00
# Top-level navigation, so get the content of this section
2016-06-05 02:48:22 +10:00
# Get all sections
2017-01-25 05:59:38 +11:00
xml = GetPlexSectionResults(
2016-06-05 02:48:22 +10:00
viewid,
2016-08-30 23:51:11 +10:00
containerSize=int(settings('limitindex')))
2016-06-05 02:48:22 +10:00
try:
xml.attrib
except AttributeError:
2016-08-30 23:51:11 +10:00
log.error("Error download section %s" % viewid)
2017-01-25 05:59:38 +11:00
return xbmcplugin.endOfDirectory(HANDLE, False)
2016-06-05 02:48:22 +10:00
else:
2016-06-13 01:22:22 +10:00
# folderid was passed so we can directly access the folder
2016-06-05 02:48:22 +10:00
xml = downloadutils.DownloadUtils().downloadUrl(
"{server}%s" % folderid)
try:
xml.attrib
except AttributeError:
2016-08-30 23:51:11 +10:00
log.error("Error downloading %s" % folderid)
2017-01-25 05:59:38 +11:00
return xbmcplugin.endOfDirectory(HANDLE, False)
2016-06-05 02:48:22 +10:00
2016-06-13 01:22:22 +10:00
# Set the folder's name
2017-01-25 05:59:38 +11:00
xbmcplugin.setPluginCategory(HANDLE,
2016-06-05 02:48:22 +10:00
xml.attrib.get('librarySectionTitle'))
2016-03-15 03:47:05 +11:00
# set the correct params for the content type
if mediatype == "photos":
2017-01-25 05:59:38 +11:00
xbmcplugin.setContent(HANDLE, 'photos')
2016-03-15 03:47:05 +11:00
# process the listing
for item in xml:
2017-01-25 05:59:38 +11:00
api = API(item)
2016-03-15 03:47:05 +11:00
if item.tag == 'Directory':
2017-01-25 05:59:38 +11:00
li = ListItem(item.attrib.get('title', 'Missing title'))
2016-03-15 03:47:05 +11:00
# for folders we add an additional browse request, passing the
# folderId
li.setProperty('IsFolder', 'true')
li.setProperty('IsPlayable', 'false')
2016-06-05 02:48:22 +10:00
path = "%s?id=%s&mode=browseplex&type=%s&folderid=%s" \
2017-01-25 05:59:38 +11:00
% (ARGV_0, viewid, mediatype, api.getKey())
api.set_listitem_artwork(li)
xbmcplugin.addDirectoryItem(handle=HANDLE,
2016-06-13 01:22:22 +10:00
url=path,
listitem=li,
isFolder=True)
2016-03-15 03:47:05 +11:00
else:
2017-01-25 05:59:38 +11:00
li = api.CreateListItemFromPlexItem()
api.set_listitem_artwork(li)
2016-03-15 03:47:05 +11:00
xbmcplugin.addDirectoryItem(
2017-01-25 05:59:38 +11:00
handle=HANDLE,
url=li.getProperty("path"),
2016-03-15 03:47:05 +11:00
listitem=li)
2017-01-25 05:59:38 +11:00
xbmcplugin.addSortMethod(HANDLE,
xbmcplugin.SORT_METHOD_VIDEO_TITLE)
2017-01-25 05:59:38 +11:00
xbmcplugin.addSortMethod(HANDLE,
xbmcplugin.SORT_METHOD_DATE)
2017-01-25 05:59:38 +11:00
xbmcplugin.addSortMethod(HANDLE,
xbmcplugin.SORT_METHOD_VIDEO_RATING)
2017-01-25 05:59:38 +11:00
xbmcplugin.addSortMethod(HANDLE,
xbmcplugin.SORT_METHOD_VIDEO_RUNTIME)
2016-03-15 03:47:05 +11:00
2016-06-13 01:22:22 +10:00
xbmcplugin.endOfDirectory(
2017-01-25 05:59:38 +11:00
handle=HANDLE,
2016-08-30 23:51:11 +10:00
cacheToDisc=settings('enableTextureCache') == 'true')
2016-03-15 23:09:51 +11:00
def getOnDeck(viewid, mediatype, tagname, limit):
"""
Retrieves Plex On Deck items, currently only for TV shows
Input:
viewid: Plex id of the library section, e.g. '1'
mediatype: Kodi mediatype, e.g. 'tvshows', 'movies',
'homevideos', 'photos'
tagname: Name of the Plex library, e.g. "My Movies"
2016-03-16 00:19:56 +11:00
limit: Max. number of items to retrieve, e.g. 50
2016-03-15 23:09:51 +11:00
"""
2017-01-25 05:59:38 +11:00
xbmcplugin.setContent(HANDLE, 'episodes')
2016-08-30 23:51:11 +10:00
appendShowTitle = settings('OnDeckTvAppendShow') == 'true'
appendSxxExx = settings('OnDeckTvAppendSeason') == 'true'
directpaths = settings('useDirectPaths') == 'true'
if settings('OnDeckTVextended') == 'false':
# Chances are that this view is used on Kodi startup
# Wait till we've connected to a PMS. At most 30s
counter = 0
2016-08-30 23:51:11 +10:00
while window('plex_authenticated') != 'true':
counter += 1
if counter >= 300:
2016-08-30 23:51:11 +10:00
log.error('Aborting On Deck view, we were not authenticated '
'for the PMS')
2017-01-25 05:59:38 +11:00
return xbmcplugin.endOfDirectory(HANDLE, False)
sleep(100)
xml = downloadutils.DownloadUtils().downloadUrl(
'{server}/library/sections/%s/onDeck' % viewid)
if xml in (None, 401):
2016-08-30 23:51:11 +10:00
log.error('Could not download PMS xml for view %s' % viewid)
2017-01-25 05:59:38 +11:00
return xbmcplugin.endOfDirectory(HANDLE)
for item in xml:
2017-01-25 05:59:38 +11:00
api = API(item)
listitem = api.CreateListItemFromPlexItem(
appendShowTitle=appendShowTitle,
appendSxxExx=appendSxxExx)
2017-01-25 05:59:38 +11:00
api.AddStreamInfo(listitem)
api.set_listitem_artwork(listitem)
2016-05-17 03:27:43 +10:00
if directpaths:
2017-01-25 05:59:38 +11:00
url = api.getFilePath()
else:
params = {
'mode': "play",
2017-01-25 05:59:38 +11:00
'id': api.getRatingKey(),
'dbid': listitem.getProperty('dbid')
}
2017-01-03 00:07:24 +11:00
url = "plugin://plugin.video.plexkodiconnect/tvshows/?%s" \
2017-01-25 05:59:38 +11:00
% urlencode(params)
xbmcplugin.addDirectoryItem(
2017-01-25 05:59:38 +11:00
handle=HANDLE,
url=url,
listitem=listitem)
return xbmcplugin.endOfDirectory(
2017-01-25 05:59:38 +11:00
handle=HANDLE,
2016-08-30 23:51:11 +10:00
cacheToDisc=settings('enableTextureCache') == 'true')
2016-03-15 23:09:51 +11:00
# if the addon is called with nextup parameter,
# we return the nextepisodes list of the given tagname
# First we get a list of all the TV shows - filtered by tag
2017-01-25 05:59:38 +11:00
params = {
'sort': {'order': "descending", 'method': "lastplayed"},
'filter': {
'and': [
{'operator': "true", 'field': "inprogress", 'value': ""},
{'operator': "is", 'field': "tag", 'value': "%s" % tagname}
]}
2016-03-15 23:09:51 +11:00
}
2017-01-25 05:59:38 +11:00
result = JSONRPC('VideoLibrary.GetTVShows').execute(params)
2016-03-15 23:09:51 +11:00
# If we found any, find the oldest unwatched show for each one.
try:
items = result['result'][mediatype]
except (KeyError, TypeError):
# Now items retrieved - empty directory
2017-01-25 05:59:38 +11:00
xbmcplugin.endOfDirectory(handle=HANDLE)
2016-03-15 23:09:51 +11:00
return
2017-01-25 05:59:38 +11:00
params = {
'sort': {'method': "episode"},
'limits': {"end": 1},
'properties': [
"title", "playcount", "season", "episode", "showtitle",
"plot", "file", "rating", "resume", "tvshowid", "art",
"streamdetails", "firstaired", "runtime", "cast", "writer",
"dateadded", "lastplayed"
],
2016-03-15 23:09:51 +11:00
}
2016-08-30 23:51:11 +10:00
if settings('ignoreSpecialsNextEpisodes') == "true":
2017-01-25 05:59:38 +11:00
params['filter'] = {
2016-03-15 23:09:51 +11:00
'and': [
{'operator': "lessthan", 'field': "playcount", 'value': "1"},
{'operator': "greaterthan", 'field': "season", 'value': "0"}
]
}
else:
2017-01-25 05:59:38 +11:00
params['filter'] = {
2016-03-15 23:09:51 +11:00
'or': [
{'operator': "lessthan", 'field': "playcount", 'value': "1"},
{'operator': "true", 'field': "inprogress", 'value': ""}
]
}
# Are there any episodes still in progress/not yet finished watching?!?
# Then we should show this episode, NOT the "next up"
2017-01-25 05:59:38 +11:00
inprog_params = {
'sort': {'method': "episode"},
'filter': {'operator': "true", 'field': "inprogress", 'value': ""},
'properties': params['properties']
2016-03-15 23:09:51 +11:00
}
count = 0
for item in items:
2017-01-25 05:59:38 +11:00
inprog_params['tvshowid'] = item['tvshowid']
result = JSONRPC('VideoLibrary.GetEpisodes').execute(inprog_params)
2016-03-15 23:09:51 +11:00
try:
episodes = result['result']['episodes']
except (KeyError, TypeError):
# No, there are no episodes not yet finished. Get "next up"
2017-01-25 05:59:38 +11:00
params['tvshowid'] = item['tvshowid']
result = JSONRPC('VideoLibrary.GetEpisodes').execute(params)
2016-03-15 23:09:51 +11:00
try:
episodes = result['result']['episodes']
except (KeyError, TypeError):
# Also no episodes currently coming up
continue
for episode in episodes:
# There will always be only 1 episode ('limit=1')
li = createListItem(episode,
appendShowTitle=appendShowTitle,
appendSxxExx=appendSxxExx)
2016-03-15 23:09:51 +11:00
xbmcplugin.addDirectoryItem(
2017-01-25 05:59:38 +11:00
handle=HANDLE,
2016-03-15 23:09:51 +11:00
url=episode['file'],
listitem=li,
2016-03-15 23:09:51 +11:00
isFolder=False)
count += 1
if count >= limit:
break
2017-01-25 05:59:38 +11:00
xbmcplugin.endOfDirectory(handle=HANDLE)
2016-04-17 21:36:41 +10:00
def watchlater():
"""
Listing for plex.tv Watch Later section (if signed in to plex.tv)
"""
2016-08-30 23:51:11 +10:00
if window('plex_token') == '':
log.error('No watch later - not signed in to plex.tv')
2017-01-25 05:59:38 +11:00
return xbmcplugin.endOfDirectory(HANDLE, False)
if window('plex_restricteduser') == 'true':
2016-08-30 23:51:11 +10:00
log.error('No watch later - restricted user')
2017-01-25 05:59:38 +11:00
return xbmcplugin.endOfDirectory(HANDLE, False)
2016-04-17 21:36:41 +10:00
xml = downloadutils.DownloadUtils().downloadUrl(
'https://plex.tv/pms/playlists/queue/all',
authenticate=False,
2016-08-30 23:51:11 +10:00
headerOptions={'X-Plex-Token': window('plex_token')})
2016-04-17 21:36:41 +10:00
if xml in (None, 401):
2016-08-30 23:51:11 +10:00
log.error('Could not download watch later list from plex.tv')
2017-01-25 05:59:38 +11:00
return xbmcplugin.endOfDirectory(HANDLE, False)
2016-04-17 21:36:41 +10:00
2016-08-30 23:51:11 +10:00
log.info('Displaying watch later plex.tv items')
2017-01-25 05:59:38 +11:00
xbmcplugin.setContent(HANDLE, 'movies')
url = "plugin://plugin.video.plexkodiconnect/"
2016-04-17 21:36:41 +10:00
params = {
2017-01-03 01:41:38 +11:00
'mode': "Plex_Node",
2016-04-17 21:36:41 +10:00
}
for item in xml:
2017-01-25 05:59:38 +11:00
api = API(item)
listitem = api.CreateListItemFromPlexItem()
api.AddStreamInfo(listitem)
api.set_listitem_artwork(listitem)
2016-04-17 21:36:41 +10:00
params['id'] = item.attrib.get('key')
2016-06-20 02:53:45 +10:00
params['viewOffset'] = item.attrib.get('viewOffset', '0')
2017-01-03 02:42:07 +11:00
params['plex_type'] = item.attrib.get('type')
2016-04-17 21:36:41 +10:00
xbmcplugin.addDirectoryItem(
2017-01-25 05:59:38 +11:00
handle=HANDLE,
url="%s?%s" % (url, urlencode(params)),
2016-04-17 21:36:41 +10:00
listitem=listitem)
xbmcplugin.endOfDirectory(
2017-01-25 05:59:38 +11:00
handle=HANDLE,
2016-08-30 23:51:11 +10:00
cacheToDisc=settings('enableTextureCache') == 'true')
2016-05-30 00:52:00 +10:00
def enterPMS():
"""
Opens dialogs for the user the plug in the PMS details
"""
# "Enter your Plex Media Server's IP or URL. Examples are:"
2017-01-25 05:59:38 +11:00
dialog('ok', lang(29999), lang(39215), '192.168.1.2', 'plex.myServer.org')
ip = dialog('input', "Enter PMS IP or URL")
2016-05-30 00:52:00 +10:00
if ip == '':
return
2017-01-25 05:59:38 +11:00
port = dialog('input', "Enter PMS port", '32400', type='{numeric}')
2016-05-30 00:52:00 +10:00
if port == '':
return
url = '%s:%s' % (ip, port)
# "Does your Plex Media Server support SSL connections?
# (https instead of http)"
2017-01-25 05:59:38 +11:00
https = dialog('yesno', lang(29999), lang(39217))
2016-05-30 00:52:00 +10:00
if https:
url = 'https://%s' % url
else:
url = 'http://%s' % url
https = 'true' if https else 'false'
2017-01-25 05:59:38 +11:00
machineIdentifier = GetMachineIdentifier(url)
2016-05-30 00:52:00 +10:00
if machineIdentifier is None:
# "Error contacting url
# Abort (Yes) or save address anyway (No)"
2017-01-25 05:59:38 +11:00
if dialog('yesno',
lang(29999),
'%s %s. %s' % (lang(39218), url, lang(39219))):
2016-05-30 00:52:00 +10:00
return
else:
2016-08-30 23:51:11 +10:00
settings('plex_machineIdentifier', '')
2016-05-30 00:52:00 +10:00
else:
2016-08-30 23:51:11 +10:00
settings('plex_machineIdentifier', machineIdentifier)
log.info('Set new PMS to https %s, ip %s, port %s, machineIdentifier %s'
2016-08-30 23:51:11 +10:00
% (https, ip, port, machineIdentifier))
settings('https', value=https)
settings('ipaddress', value=ip)
settings('port', value=port)
# Chances are this is a local PMS, so disable SSL certificate check
2016-08-30 23:51:11 +10:00
settings('sslverify', value='false')
2016-05-30 00:52:00 +10:00
# Sign out to trigger new login
if __LogOut():
# Only login again if logout was successful
__LogIn()
def __LogIn():
2016-05-30 00:52:00 +10:00
"""
Resets (clears) window properties to enable (re-)login:
suspend_Userclient
plex_runLibScan: set to 'full' to trigger lib sync
suspend_LibraryThread is cleared in service.py if user was signed out!
"""
2016-08-30 23:51:11 +10:00
window('plex_runLibScan', value='full')
2016-05-30 00:52:00 +10:00
# Restart user client
2016-08-30 23:51:11 +10:00
window('suspend_Userclient', clear=True)
2016-05-30 00:52:00 +10:00
def __LogOut():
2016-05-30 00:52:00 +10:00
"""
Finishes lib scans, logs out user. The following window attributes are set:
suspend_LibraryThread: 'true'
suspend_Userclient: 'true'
Returns True if successfully signed out, False otherwise
"""
# Resetting, please wait
2017-01-25 05:59:38 +11:00
dialog('notification',
lang(29999),
lang(39207),
icon='{plex}',
time=3000,
sound=False)
2016-05-30 00:52:00 +10:00
# Pause library sync thread
2016-08-30 23:51:11 +10:00
window('suspend_LibraryThread', value='true')
2016-05-30 00:52:00 +10:00
# Wait max for 10 seconds for all lib scans to shutdown
counter = 0
2016-08-30 23:51:11 +10:00
while window('plex_dbScan') == 'true':
2016-05-30 00:52:00 +10:00
if counter > 200:
# Failed to reset PMS and plex.tv connects. Try to restart Kodi.
2017-01-25 05:59:38 +11:00
dialog('ok', lang(29999), lang(39208))
2016-05-30 00:52:00 +10:00
# Resuming threads, just in case
2016-08-30 23:51:11 +10:00
window('suspend_LibraryThread', clear=True)
log.error("Could not stop library sync, aborting")
2016-05-30 00:52:00 +10:00
return False
counter += 1
2017-01-25 05:59:38 +11:00
sleep(50)
2016-08-30 23:51:11 +10:00
log.debug("Successfully stopped library sync")
2016-05-30 00:52:00 +10:00
# Log out currently signed in user:
2016-08-30 23:51:11 +10:00
window('plex_serverStatus', value="401")
# Above method needs to have run its course! Hence wait
counter = 0
2016-08-30 23:51:11 +10:00
while window('plex_serverStatus') == "401":
if counter > 100:
# 'Failed to reset PKC. Try to restart Kodi.'
2017-01-25 05:59:38 +11:00
dialog('ok', lang(29999), lang(39208))
2016-08-30 23:51:11 +10:00
log.error("Could not sign out user, aborting")
return False
counter += 1
2017-01-25 05:59:38 +11:00
sleep(50)
# Suspend the user client during procedure
2016-08-30 23:51:11 +10:00
window('suspend_Userclient', value='true')
2016-05-30 00:52:00 +10:00
return True