Merge branch 'develop'
This commit is contained in:
commit
8363c04ae3
21 changed files with 347 additions and 216 deletions
|
@ -1,7 +1,7 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
<addon id="plugin.video.plexkodiconnect"
|
<addon id="plugin.video.plexkodiconnect"
|
||||||
name="PlexKodiConnect"
|
name="PlexKodiConnect"
|
||||||
version="1.0.3"
|
version="1.0.4"
|
||||||
provider-name="croneter">
|
provider-name="croneter">
|
||||||
<requires>
|
<requires>
|
||||||
<import addon="xbmc.python" version="2.1.0"/>
|
<import addon="xbmc.python" version="2.1.0"/>
|
||||||
|
|
|
@ -1,3 +1,14 @@
|
||||||
|
version 1.0.4
|
||||||
|
- Sleep for a while in loops - drastically reduces CPU load
|
||||||
|
- Connect to remote PMS!
|
||||||
|
- New Setting to reset all PMS and the plex.tv connection
|
||||||
|
- Correct encoding
|
||||||
|
- Much shorter download timeouts
|
||||||
|
- Improve sync resiliance and GDM discovery
|
||||||
|
- Reduce number of unsuccesful retries to 3 before telling user
|
||||||
|
- Clean-up library sync loop
|
||||||
|
- Language strings for library sync
|
||||||
|
|
||||||
version 1.0.3
|
version 1.0.3
|
||||||
- Hotfix database minimum version = 1.0.2
|
- Hotfix database minimum version = 1.0.2
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@ class Main:
|
||||||
'companion': entrypoint.plexCompanion,
|
'companion': entrypoint.plexCompanion,
|
||||||
'switchuser': entrypoint.switchPlexUser,
|
'switchuser': entrypoint.switchPlexUser,
|
||||||
'deviceid': entrypoint.resetDeviceId,
|
'deviceid': entrypoint.resetDeviceId,
|
||||||
'doPlexTvLogin': entrypoint.doPlexTvLogin
|
'reConnect': entrypoint.reConnect
|
||||||
}
|
}
|
||||||
|
|
||||||
if "/extrafanart" in sys.argv[0]:
|
if "/extrafanart" in sys.argv[0]:
|
||||||
|
|
|
@ -362,7 +362,7 @@
|
||||||
<string id="39021">[COLOR yellow]Sync Emby Theme Media to Kodi[/COLOR]</string>
|
<string id="39021">[COLOR yellow]Sync Emby Theme Media to Kodi[/COLOR]</string>
|
||||||
<string id="39022"> (local)</string>
|
<string id="39022"> (local)</string>
|
||||||
<string id="39023">Failed to authenticate. Did you login to plex.tv?</string>
|
<string id="39023">Failed to authenticate. Did you login to plex.tv?</string>
|
||||||
<string id="39024">[COLOR yellow]Log into plex.tv[/COLOR]</string>
|
<string id="39024">[COLOR yellow]Reset PMS and plex.tv connections to re-login[/COLOR]</string>
|
||||||
<string id="39025">Automatically log into plex.tv on startup</string>
|
<string id="39025">Automatically log into plex.tv on startup</string>
|
||||||
<string id="39026">Enable constant background sync (restart Kodi!)</string>
|
<string id="39026">Enable constant background sync (restart Kodi!)</string>
|
||||||
|
|
||||||
|
@ -375,6 +375,9 @@
|
||||||
<string id="39204">Perform manual library sync</string>
|
<string id="39204">Perform manual library sync</string>
|
||||||
<string id="39205">Unable to run the sync, the add-on is not connected to a Plex server.</string>
|
<string id="39205">Unable to run the sync, the add-on is not connected to a Plex server.</string>
|
||||||
<string id="39206">Plex might lock your account if you fail to log in too many times. Proceed anyway?</string>
|
<string id="39206">Plex might lock your account if you fail to log in too many times. Proceed anyway?</string>
|
||||||
|
<string id="39207">Reseting PMS connections, please wait</string>
|
||||||
|
<string id="39208">Failed to reset PMS and plex.tv connects. Try to restart Kodi.</string>
|
||||||
|
<string id="39209">[COLOR yellow]Log-in to plex.tv[/COLOR]</string>
|
||||||
|
|
||||||
|
|
||||||
<!-- Plex Artwork.py -->
|
<!-- Plex Artwork.py -->
|
||||||
|
@ -393,4 +396,13 @@
|
||||||
<string id="39308">Could not log in user </string>
|
<string id="39308">Could not log in user </string>
|
||||||
<string id="39309">Please try again.</string>
|
<string id="39309">Please try again.</string>
|
||||||
|
|
||||||
|
<!-- Plex Librarysync.py -->
|
||||||
|
<string id="39400">Library sync thread has crashed. You should restart Kodi now. Please report this on the forum</string>
|
||||||
|
<string id="39401">Detected Kodi database needs to be recreated for this version. This might take a while. Proceed?</string>
|
||||||
|
<string id="39402"> may not work correctly until the database is reset.</string>
|
||||||
|
<string id="39403">Cancelling the database syncing process. Current Kodi version is unsupported. Please verify your logs for more info.</string>
|
||||||
|
<string id="39404">Startup syncing process failed repeatedly. Try restarting Kodi. Stopping Sync for now.</string>
|
||||||
|
<string id="39405">Plex playlists/nodes refreshed</string>
|
||||||
|
<string id="39406">Plex playlists/nodes refresh failed</string>
|
||||||
|
|
||||||
</strings>
|
</strings>
|
||||||
|
|
|
@ -293,7 +293,7 @@
|
||||||
<string id="39021">[COLOR yellow]Plex Themes zu Kodi synchronisieren[/COLOR]</string>
|
<string id="39021">[COLOR yellow]Plex Themes zu Kodi synchronisieren[/COLOR]</string>
|
||||||
<string id="39022"> (lokal)</string>
|
<string id="39022"> (lokal)</string>
|
||||||
<string id="39023">Plex Media Server Authentifizierung fehlgeschlagen. Haben Sie sich bei plex.tv eingeloggt?</string>
|
<string id="39023">Plex Media Server Authentifizierung fehlgeschlagen. Haben Sie sich bei plex.tv eingeloggt?</string>
|
||||||
<string id="39024">[COLOR yellow]Bei plex.tv einloggen[/COLOR]</string>
|
<string id="39024">[COLOR yellow]PMS und plex.tv Verbindungen zurücksetzen für erneuten Login[/COLOR]</string>
|
||||||
<string id="39025">Automatisch beim Starten bei plex.tv einloggen</string>
|
<string id="39025">Automatisch beim Starten bei plex.tv einloggen</string>
|
||||||
<string id="39026">Laufende Synchronisierung im Hintergrund aktivieren (Neustart!)</string>
|
<string id="39026">Laufende Synchronisierung im Hintergrund aktivieren (Neustart!)</string>
|
||||||
|
|
||||||
|
@ -305,6 +305,11 @@
|
||||||
<string id="39204">Manuellen Scan der Plex Bibliotheken starten</string>
|
<string id="39204">Manuellen Scan der Plex Bibliotheken starten</string>
|
||||||
<string id="39205">Plex Bibliothek kann nicht gescannt werden, da keine Verbindung mit einem Plex Server besteht.</string>
|
<string id="39205">Plex Bibliothek kann nicht gescannt werden, da keine Verbindung mit einem Plex Server besteht.</string>
|
||||||
<string id="39206">Plex könnte möglicherweise Ihren Account sperren, wenn Sie zu oft versuchen, sich erfolglos anzumelden. Trotzdem fortfahren?</string>
|
<string id="39206">Plex könnte möglicherweise Ihren Account sperren, wenn Sie zu oft versuchen, sich erfolglos anzumelden. Trotzdem fortfahren?</string>
|
||||||
|
<string id="39207">PMS Verbindungen werden zurückgesetzt</string>
|
||||||
|
<string id="39208">PMS und plex.tv Verbindungen konnten nicht zurückgesetzt werden. Bitte versuchen Sie, Kodi neu zu starten, um das Problem zu beheben.</string>
|
||||||
|
<string id="39209">[COLOR yellow]Bei plex.tv einloggen[/COLOR]</string>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Plex Artwork.py -->
|
<!-- Plex Artwork.py -->
|
||||||
<string id="39250">Alle Plex Bilder in Kodi zwischenzuspeichern kann sehr lange dauern. Möchten Sie wirklich fortfahren?</string>
|
<string id="39250">Alle Plex Bilder in Kodi zwischenzuspeichern kann sehr lange dauern. Möchten Sie wirklich fortfahren?</string>
|
||||||
|
@ -322,4 +327,13 @@
|
||||||
<string id="39308">Anmeldung fehlgeschlagen für Benutzer </string>
|
<string id="39308">Anmeldung fehlgeschlagen für Benutzer </string>
|
||||||
<string id="39309">Bitte erneut versuchen.</string>
|
<string id="39309">Bitte erneut versuchen.</string>
|
||||||
|
|
||||||
|
<!-- Plex Librarysync.py -->
|
||||||
|
<string id="39400">Die Synchronisierung der Plex Bibliotheken ist abgestürzt. Bitte Kodi neu starten. Danke, wenn Sie sich die Zeit nehmen und im Plex Forum vom Absturz berichten.</string>
|
||||||
|
<string id="39401">Die Kodi Datenbank muss neu kreiert werden für diese Version. Das kann eine Weile dauern. Fortfahren?</string>
|
||||||
|
<string id="39402"> funktioniert möglicherweise nicht richtig, bis die Kodi Datenbank zurückgesetzt worden ist.</string>
|
||||||
|
<string id="39403">Synchronisierung der Plex Bibliotheken wird abgebrochen. Die momentane Kodi Version wird nicht unterstützt. Für weitere Informationen bitte das Kodi Log konsultieren.</string>
|
||||||
|
<string id="39404">Der Startup Synchronisations-Prozess der Plex Bibliotheken ist mehrmals fehlgeschlagen. Bitte Kodi neu starten. Synch wird jetzt gestoppt.</string>
|
||||||
|
<string id="39405">Plex Playlisten/Nodes aktualisiert</string>
|
||||||
|
<string id="39406">Plex Playlisten/Nodes Aktualisierung fehlgeschlagen</string>
|
||||||
|
|
||||||
</strings>
|
</strings>
|
||||||
|
|
|
@ -55,7 +55,7 @@ import re
|
||||||
import json
|
import json
|
||||||
from urllib import urlencode, quote_plus
|
from urllib import urlencode, quote_plus
|
||||||
|
|
||||||
from PlexFunctions import PlexToKodiTimefactor
|
from PlexFunctions import PlexToKodiTimefactor, PMSHttpsEnabled
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import xml.etree.cElementTree as etree
|
import xml.etree.cElementTree as etree
|
||||||
|
@ -131,17 +131,14 @@ class PlexAPI():
|
||||||
dialog = xbmcgui.Dialog()
|
dialog = xbmcgui.Dialog()
|
||||||
while retrievedPlexLogin == '' and plexLogin != '':
|
while retrievedPlexLogin == '' and plexLogin != '':
|
||||||
# Enter plex.tv username. Or nothing to cancel.
|
# Enter plex.tv username. Or nothing to cancel.
|
||||||
plexLogin = dialog.input(
|
plexLogin = dialog.input(self.addonName + string(39300),
|
||||||
self.addonName.encode('utf-8') + string(39300).encode('utf-8'),
|
type=xbmcgui.INPUT_ALPHANUM)
|
||||||
type=xbmcgui.INPUT_ALPHANUM,
|
|
||||||
)
|
|
||||||
if plexLogin != "":
|
if plexLogin != "":
|
||||||
# Enter password for plex.tv user
|
# Enter password for plex.tv user
|
||||||
plexPassword = dialog.input(
|
plexPassword = dialog.input(
|
||||||
string(39301).encode('utf-8') + plexLogin.encode('utf-8'),
|
string(39301) + plexLogin,
|
||||||
type=xbmcgui.INPUT_ALPHANUM,
|
type=xbmcgui.INPUT_ALPHANUM,
|
||||||
option=xbmcgui.ALPHANUM_HIDE_INPUT
|
option=xbmcgui.ALPHANUM_HIDE_INPUT)
|
||||||
)
|
|
||||||
retrievedPlexLogin, authtoken = self.MyPlexSignIn(
|
retrievedPlexLogin, authtoken = self.MyPlexSignIn(
|
||||||
plexLogin,
|
plexLogin,
|
||||||
plexPassword,
|
plexPassword,
|
||||||
|
@ -151,8 +148,7 @@ class PlexAPI():
|
||||||
if plexLogin == '':
|
if plexLogin == '':
|
||||||
# Could not sign in user
|
# Could not sign in user
|
||||||
dialog.ok(self.addonName,
|
dialog.ok(self.addonName,
|
||||||
string(39302).encode('utf-8')
|
string(39302) + plexLogin)
|
||||||
+ plexLogin.encode('utf-8'))
|
|
||||||
# Write to Kodi settings file
|
# Write to Kodi settings file
|
||||||
utils.settings('plexLogin', value=retrievedPlexLogin)
|
utils.settings('plexLogin', value=retrievedPlexLogin)
|
||||||
utils.settings('plexToken', value=authtoken)
|
utils.settings('plexToken', value=authtoken)
|
||||||
|
@ -177,12 +173,12 @@ class PlexAPI():
|
||||||
dialog = xbmcgui.Dialog()
|
dialog = xbmcgui.Dialog()
|
||||||
if not code:
|
if not code:
|
||||||
# Problems trying to contact plex.tv. Try again later
|
# Problems trying to contact plex.tv. Try again later
|
||||||
dialog.ok(self.addonName, string(39303).encode('utf-8'))
|
dialog.ok(self.addonName, string(39303))
|
||||||
return False
|
return False
|
||||||
# Go to https://plex.tv/pin and enter the code:
|
# Go to https://plex.tv/pin and enter the code:
|
||||||
answer = dialog.yesno(self.addonName,
|
answer = dialog.yesno(self.addonName,
|
||||||
(string(39304) + "\n\n").encode('utf-8'),
|
string(39304) + "\n\n",
|
||||||
code.encode('utf-8'))
|
code)
|
||||||
if not answer:
|
if not answer:
|
||||||
return False
|
return False
|
||||||
count = 0
|
count = 0
|
||||||
|
@ -196,7 +192,7 @@ class PlexAPI():
|
||||||
count += 1
|
count += 1
|
||||||
if not xml:
|
if not xml:
|
||||||
# Could not sign in to plex.tv Try again later
|
# Could not sign in to plex.tv Try again later
|
||||||
dialog.ok(self.addonName, string(39305).encode('utf-8'))
|
dialog.ok(self.addonName, string(39305))
|
||||||
return False
|
return False
|
||||||
# Parse xml
|
# Parse xml
|
||||||
userid = xml.attrib.get('id')
|
userid = xml.attrib.get('id')
|
||||||
|
@ -299,13 +295,13 @@ class PlexAPI():
|
||||||
verify=verify,
|
verify=verify,
|
||||||
timeout=timeout)
|
timeout=timeout)
|
||||||
except requests.exceptions.ConnectionError as e:
|
except requests.exceptions.ConnectionError as e:
|
||||||
self.logMsg("Server is offline or cannot be reached. Url: %s."
|
self.logMsg("Server is offline or cannot be reached. Url: %s. "
|
||||||
"Header: %s. Error message: %s"
|
"Error message: %s"
|
||||||
% (url, header, e), -1)
|
% (url, e), -1)
|
||||||
return False
|
return False
|
||||||
except requests.exceptions.ReadTimeout:
|
except requests.exceptions.ReadTimeout:
|
||||||
self.logMsg("Server timeout reached for Url %s with header %s"
|
self.logMsg("Server timeout reached for Url %s"
|
||||||
% (url, header), -1)
|
% url, -1)
|
||||||
return False
|
return False
|
||||||
# We received an answer from the server, but not as expected.
|
# We received an answer from the server, but not as expected.
|
||||||
if answer.status_code >= 400:
|
if answer.status_code >= 400:
|
||||||
|
@ -634,6 +630,12 @@ class PlexAPI():
|
||||||
self.getPMSListFromMyPlex(ATV_udid, authtoken)
|
self.getPMSListFromMyPlex(ATV_udid, authtoken)
|
||||||
# all servers - update enableGzip
|
# all servers - update enableGzip
|
||||||
for uuid_id in self.g_PMS.get(ATV_udid, {}):
|
for uuid_id in self.g_PMS.get(ATV_udid, {}):
|
||||||
|
# Ping to check whether we need HTTPs or HTTP
|
||||||
|
url = (self.getPMSProperty(ATV_udid, uuid_id, 'ip') + ':'
|
||||||
|
+ self.getPMSProperty(ATV_udid, uuid_id, 'port'))
|
||||||
|
if PMSHttpsEnabled(url):
|
||||||
|
self.logMsg('PMS %s talks HTTPS' % uuid_id, 1)
|
||||||
|
self.updatePMSProperty(ATV_udid, uuid_id, 'scheme', 'https')
|
||||||
# enable Gzip if not on same host, local&remote PMS depending
|
# enable Gzip if not on same host, local&remote PMS depending
|
||||||
# on setting
|
# on setting
|
||||||
enableGzip = (not self.getPMSProperty(ATV_udid, uuid_id, 'ip') == IP_self) \
|
enableGzip = (not self.getPMSProperty(ATV_udid, uuid_id, 'ip') == IP_self) \
|
||||||
|
@ -1089,7 +1091,7 @@ class PlexAPI():
|
||||||
if usernumber > 1:
|
if usernumber > 1:
|
||||||
# Select user
|
# Select user
|
||||||
user_select = dialog.select(
|
user_select = dialog.select(
|
||||||
(self.addonName + string(39306)).encode('utf-8'),
|
self.addonName + string(39306),
|
||||||
userlistCoded)
|
userlistCoded)
|
||||||
if user_select == -1:
|
if user_select == -1:
|
||||||
self.logMsg("No user selected.", 1)
|
self.logMsg("No user selected.", 1)
|
||||||
|
@ -1108,7 +1110,7 @@ class PlexAPI():
|
||||||
# Please enter pin for user
|
# Please enter pin for user
|
||||||
self.logMsg('Asking for users PIN', 1)
|
self.logMsg('Asking for users PIN', 1)
|
||||||
pin = dialog.input(
|
pin = dialog.input(
|
||||||
(string(39307) + selected_user).encode('utf-8'),
|
string(39307) + selected_user,
|
||||||
type=xbmcgui.INPUT_NUMERIC,
|
type=xbmcgui.INPUT_NUMERIC,
|
||||||
option=xbmcgui.ALPHANUM_HIDE_INPUT)
|
option=xbmcgui.ALPHANUM_HIDE_INPUT)
|
||||||
# User chose to cancel
|
# User chose to cancel
|
||||||
|
@ -1129,11 +1131,9 @@ class PlexAPI():
|
||||||
# Couldn't get user auth
|
# Couldn't get user auth
|
||||||
if not username:
|
if not username:
|
||||||
# Could not login user, please try again
|
# Could not login user, please try again
|
||||||
if not dialog.yesno(
|
if not dialog.yesno(self.addonName,
|
||||||
self.addonName,
|
string(39308) + selected_user,
|
||||||
(string(39308) + selected_user).encode('utf-8'),
|
string(39309)):
|
||||||
string(39309).encode('utf-8')
|
|
||||||
):
|
|
||||||
# User chose to cancel
|
# User chose to cancel
|
||||||
break
|
break
|
||||||
# Successfully retrieved: break out of while loop
|
# Successfully retrieved: break out of while loop
|
||||||
|
|
|
@ -87,9 +87,11 @@ class PlexCompanion(threading.Thread):
|
||||||
|
|
||||||
subscribers.subMgr.notify()
|
subscribers.subMgr.notify()
|
||||||
settings['serverList'] = self.client.getServerList()
|
settings['serverList'] = self.client.getServerList()
|
||||||
|
xbmc.sleep(50)
|
||||||
except:
|
except:
|
||||||
self.logMsg("Error in loop, continuing anyway", 1)
|
self.logMsg("Error in loop, continuing anyway", 1)
|
||||||
self.logMsg(traceback.print_exc(), 1)
|
self.logMsg(traceback.print_exc(), 1)
|
||||||
|
xbmc.sleep(50)
|
||||||
|
|
||||||
self.client.stop_all()
|
self.client.stop_all()
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -347,3 +347,24 @@ def getPlexRepeat(kodiRepeat):
|
||||||
'all': '2' # does this work?!?
|
'all': '2' # does this work?!?
|
||||||
}
|
}
|
||||||
return plexRepeat.get(kodiRepeat)
|
return plexRepeat.get(kodiRepeat)
|
||||||
|
|
||||||
|
|
||||||
|
def PMSHttpsEnabled(url):
|
||||||
|
"""
|
||||||
|
Returns True if the PMS wants to talk https, False otherwise
|
||||||
|
|
||||||
|
With with e.g. url=192.168.0.1:32400 (NO http/https)
|
||||||
|
|
||||||
|
This is done by GET /identity (returns an error if https is enabled and we
|
||||||
|
are trying to use http)
|
||||||
|
"""
|
||||||
|
xml = downloadutils.DownloadUtils().downloadUrl('http://%s/identity' % url)
|
||||||
|
try:
|
||||||
|
# received a valid XML - http connection is possible
|
||||||
|
xml.attrib
|
||||||
|
logMsg('PMSHttpsEnabled', 'PMS on %s talks HTTP' % url, 1)
|
||||||
|
return False
|
||||||
|
except:
|
||||||
|
# couldn't get an xml - switch to https traffic
|
||||||
|
logMsg('PMSHttpsEnabled', 'PMS on %s talks HTTPS' % url, 1)
|
||||||
|
return True
|
||||||
|
|
|
@ -37,7 +37,7 @@ class DownloadUtils():
|
||||||
|
|
||||||
# Requests session
|
# Requests session
|
||||||
s = None
|
s = None
|
||||||
timeout = 30
|
timeout = 3
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
|
@ -359,7 +359,7 @@ class DownloadUtils():
|
||||||
except requests.exceptions.ConnectionError as e:
|
except requests.exceptions.ConnectionError as e:
|
||||||
# Make the addon aware of status
|
# Make the addon aware of status
|
||||||
if utils.window('emby_online') != "false":
|
if utils.window('emby_online') != "false":
|
||||||
self.logMsg("Server unreachable at: %s" % url, 0)
|
self.logMsg("Server unreachable at: %s" % url, -1)
|
||||||
self.logMsg(e, 2)
|
self.logMsg(e, 2)
|
||||||
utils.window('emby_online', value="false")
|
utils.window('emby_online', value="false")
|
||||||
|
|
||||||
|
|
|
@ -72,18 +72,48 @@ def plexCompanion(fullurl, params):
|
||||||
title, "Not knowing what to do for now - no playQueue sent", -1)
|
title, "Not knowing what to do for now - no playQueue sent", -1)
|
||||||
|
|
||||||
|
|
||||||
def doPlexTvLogin():
|
def reConnect():
|
||||||
"""
|
"""
|
||||||
Triggers login to plex.tv
|
Triggers login to plex.tv and re-authorization
|
||||||
"""
|
"""
|
||||||
|
string = xbmcaddon.Addon().getLocalizedString
|
||||||
|
utils.logMsg("entrypoint reConnect",
|
||||||
|
"Connection resets requested", 0)
|
||||||
|
# Pause library sync thread - user needs to be auth in order to sync
|
||||||
|
utils.window('suspend_LibraryThread', value='true')
|
||||||
# Suspend the user client during procedure
|
# Suspend the user client during procedure
|
||||||
utils.window('suspend_Userclient', value='true')
|
utils.window('suspend_Userclient', value='true')
|
||||||
|
dialog = xbmcgui.Dialog()
|
||||||
|
dialog.notification(
|
||||||
|
heading=addonName,
|
||||||
|
message=string(39207),
|
||||||
|
icon="special://home/addons/plugin.video.plexkodiconnect/icon.png",
|
||||||
|
sound=False)
|
||||||
|
|
||||||
|
# Wait max for 20 seconds for all lib scans to finish
|
||||||
|
counter = 0
|
||||||
|
while utils.window('emby_dbScan') == 'true':
|
||||||
|
xbmc.sleep(1000)
|
||||||
|
counter += 1
|
||||||
|
if counter > 20:
|
||||||
|
dialog.ok(
|
||||||
|
heading=addonName,
|
||||||
|
message=string(39208),
|
||||||
|
)
|
||||||
|
# Resuming threads, just in case
|
||||||
|
utils.window('suspend_LibraryThread', clear=True)
|
||||||
|
utils.window('suspend_Userclient', clear=True)
|
||||||
|
# Abort reConnection
|
||||||
|
return
|
||||||
|
|
||||||
import initialsetup
|
import initialsetup
|
||||||
initialsetup.InitialSetup().setup(forcePlexTV=True)
|
initialsetup.InitialSetup().setup(forcePlexTV=True)
|
||||||
utils.logMsg("PLEX", "Reset login attempts.", 1)
|
# Log out currently signed in user:
|
||||||
utils.window('emby_serverStatus', value="Auth")
|
utils.window('emby_serverStatus', value="401")
|
||||||
# Restart user client
|
# Restart user client
|
||||||
utils.window('suspend_Userclient', clear=True)
|
utils.window('suspend_Userclient', clear=True)
|
||||||
|
# Request lib sync to get user view data (e.g. watched/unwatched)
|
||||||
|
utils.window('plex_runLibScan', value='full')
|
||||||
|
|
||||||
|
|
||||||
def PassPlaylist(xml, resume=None):
|
def PassPlaylist(xml, resume=None):
|
||||||
|
@ -155,7 +185,7 @@ def resetAuth():
|
||||||
string = xbmcaddon.Addon().getLocalizedString
|
string = xbmcaddon.Addon().getLocalizedString
|
||||||
resp = xbmcgui.Dialog().yesno(
|
resp = xbmcgui.Dialog().yesno(
|
||||||
heading="Warning",
|
heading="Warning",
|
||||||
line1=string(39206).encode('utf-8'))
|
line1=string(39206))
|
||||||
if resp == 1:
|
if resp == 1:
|
||||||
utils.logMsg("PLEX", "Reset login attempts.", 1)
|
utils.logMsg("PLEX", "Reset login attempts.", 1)
|
||||||
utils.window('emby_serverStatus', value="Auth")
|
utils.window('emby_serverStatus', value="Auth")
|
||||||
|
@ -225,14 +255,14 @@ def resetDeviceId():
|
||||||
"Failed to generate a new device Id: %s" % e, 1)
|
"Failed to generate a new device Id: %s" % e, 1)
|
||||||
dialog.ok(
|
dialog.ok(
|
||||||
heading=addonName,
|
heading=addonName,
|
||||||
line1=language(33032).encode('utf-8'))
|
line1=language(33032))
|
||||||
else:
|
else:
|
||||||
utils.logMsg(addonName,
|
utils.logMsg(addonName,
|
||||||
"Successfully removed old deviceId: %s New deviceId: %s"
|
"Successfully removed old deviceId: %s New deviceId: %s"
|
||||||
% (deviceId_old, deviceId), 1)
|
% (deviceId_old, deviceId), 1)
|
||||||
dialog.ok(
|
dialog.ok(
|
||||||
heading=addonName,
|
heading=addonName,
|
||||||
line1=language(33033).encode('utf-8'))
|
line1=language(33033))
|
||||||
xbmc.executebuiltin('RestartApp')
|
xbmc.executebuiltin('RestartApp')
|
||||||
|
|
||||||
##### ADD ADDITIONAL USERS #####
|
##### ADD ADDITIONAL USERS #####
|
||||||
|
@ -1159,6 +1189,6 @@ def RunLibScan(mode):
|
||||||
# Server is not online, do not run the sync
|
# Server is not online, do not run the sync
|
||||||
string = xbmcaddon.Addon().getLocalizedString
|
string = xbmcaddon.Addon().getLocalizedString
|
||||||
xbmcgui.Dialog().ok(heading=addonName,
|
xbmcgui.Dialog().ok(heading=addonName,
|
||||||
line1=string(39205).encode('utf-8'))
|
line1=string(39205))
|
||||||
else:
|
else:
|
||||||
utils.window('plex_runLibScan', value='full')
|
utils.window('plex_runLibScan', value='full')
|
||||||
|
|
|
@ -40,7 +40,7 @@ class image_cache_thread(threading.Thread):
|
||||||
"http://%s:%s/image/image://%s"
|
"http://%s:%s/image/image://%s"
|
||||||
% (self.xbmc_host, self.xbmc_port, self.urlToProcess)),
|
% (self.xbmc_host, self.xbmc_port, self.urlToProcess)),
|
||||||
auth=(self.xbmc_username, self.xbmc_password),
|
auth=(self.xbmc_username, self.xbmc_password),
|
||||||
timeout=(35.1, 35.1))
|
timeout=(0.1, 0.1))
|
||||||
# We don't need the result
|
# We don't need the result
|
||||||
except: pass
|
except: pass
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ class InitialSetup():
|
||||||
plexLogin = plexdict['plexLogin']
|
plexLogin = plexdict['plexLogin']
|
||||||
plexToken = plexdict['plexToken']
|
plexToken = plexdict['plexToken']
|
||||||
plexid = plexdict['plexid']
|
plexid = plexdict['plexid']
|
||||||
self.logMsg('Plex info retrieved from settings: %s' % plexdict, 1)
|
self.logMsg('Plex info retrieved from settings', 1)
|
||||||
|
|
||||||
dialog = xbmcgui.Dialog()
|
dialog = xbmcgui.Dialog()
|
||||||
|
|
||||||
|
@ -57,10 +57,8 @@ class InitialSetup():
|
||||||
# Delete token in the settings
|
# Delete token in the settings
|
||||||
utils.settings('plexToken', value='')
|
utils.settings('plexToken', value='')
|
||||||
# Could not login, please try again
|
# Could not login, please try again
|
||||||
dialog.ok(
|
dialog.ok(self.addonName,
|
||||||
self.addonName,
|
string(39009))
|
||||||
string(39009).encode('utf-8')
|
|
||||||
)
|
|
||||||
result = self.plx.PlexTvSignInWithPin()
|
result = self.plx.PlexTvSignInWithPin()
|
||||||
if result:
|
if result:
|
||||||
plexLogin = result['username']
|
plexLogin = result['username']
|
||||||
|
@ -68,10 +66,8 @@ class InitialSetup():
|
||||||
plexid = result['plexid']
|
plexid = result['plexid']
|
||||||
elif chk is False or chk >= 400:
|
elif chk is False or chk >= 400:
|
||||||
# Problems connecting to plex.tv. Network or internet issue?
|
# Problems connecting to plex.tv. Network or internet issue?
|
||||||
dialog.ok(
|
dialog.ok(self.addonName,
|
||||||
self.addonName,
|
string(39010))
|
||||||
string(39010).encode('utf-8')
|
|
||||||
)
|
|
||||||
# If a Plex server IP has already been set, return.
|
# If a Plex server IP has already been set, return.
|
||||||
if server and forcePlexTV is False:
|
if server and forcePlexTV is False:
|
||||||
self.logMsg("Server is already set.", 0)
|
self.logMsg("Server is already set.", 0)
|
||||||
|
@ -100,8 +96,8 @@ class InitialSetup():
|
||||||
self.logMsg("Result of setting g_PMS variable: %s"
|
self.logMsg("Result of setting g_PMS variable: %s"
|
||||||
% self.plx.g_PMS, 1)
|
% self.plx.g_PMS, 1)
|
||||||
isconnected = False
|
isconnected = False
|
||||||
serverlist = self.plx.returnServerList(
|
serverlist = self.plx.returnServerList(clientId,
|
||||||
clientId, self.plx.g_PMS)
|
self.plx.g_PMS)
|
||||||
self.logMsg('PMS serverlist: %s' % serverlist)
|
self.logMsg('PMS serverlist: %s' % serverlist)
|
||||||
# Let user pick server from a list
|
# Let user pick server from a list
|
||||||
# Get a nicer list
|
# Get a nicer list
|
||||||
|
@ -110,22 +106,27 @@ class InitialSetup():
|
||||||
if len(serverlist) == 0:
|
if len(serverlist) == 0:
|
||||||
dialog.ok(
|
dialog.ok(
|
||||||
self.addonName,
|
self.addonName,
|
||||||
string(39011).encode('utf-8')
|
string(39011)
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
for server in serverlist:
|
for server in serverlist:
|
||||||
if server['local'] == '1':
|
if server['local'] == '1':
|
||||||
# server is in the same network as client. Add "local"
|
# server is in the same network as client. Add "local"
|
||||||
dialoglist.append(
|
dialoglist.append(
|
||||||
server['name'].encode('utf-8')
|
server['name']
|
||||||
+ string(39022).encode('utf-8'))
|
+ string(39022))
|
||||||
else:
|
else:
|
||||||
dialoglist.append(server['name'].encode('utf-8'))
|
dialoglist.append(server['name'])
|
||||||
resp = dialog.select(string(39012).encode('utf-8'), dialoglist)
|
resp = dialog.select(string(39012), dialoglist)
|
||||||
server = serverlist[resp]
|
server = serverlist[resp]
|
||||||
activeServer = server['machineIdentifier']
|
activeServer = server['machineIdentifier']
|
||||||
url = server['scheme'] + '://' + server['ip'] + ':' + \
|
# Re-direct via plex if remote - will lead to the correct SSL
|
||||||
server['port']
|
# certificate
|
||||||
|
if server['local'] == '1':
|
||||||
|
url = server['scheme'] + '://' + server['ip'] + ':' \
|
||||||
|
+ server['port']
|
||||||
|
else:
|
||||||
|
url = server['baseURL']
|
||||||
# Deactive SSL verification if the server is local!
|
# Deactive SSL verification if the server is local!
|
||||||
if server['local'] == '1':
|
if server['local'] == '1':
|
||||||
utils.settings('sslverify', 'false')
|
utils.settings('sslverify', 'false')
|
||||||
|
@ -146,9 +147,8 @@ class InitialSetup():
|
||||||
# Not yet authorized for Plex server
|
# Not yet authorized for Plex server
|
||||||
# Please sign in to plex.tv
|
# Please sign in to plex.tv
|
||||||
dialog.ok(self.addonName,
|
dialog.ok(self.addonName,
|
||||||
string(39013).encode('utf-8')
|
string(39013) + server['name'],
|
||||||
+ server['name'].encode('utf-8'),
|
string(39014))
|
||||||
string(39014).encode('utf-8'))
|
|
||||||
result = self.plx.PlexTvSignInWithPin()
|
result = self.plx.PlexTvSignInWithPin()
|
||||||
if result:
|
if result:
|
||||||
plexLogin = result['username']
|
plexLogin = result['username']
|
||||||
|
@ -161,7 +161,7 @@ class InitialSetup():
|
||||||
elif chk >= 400 or chk is False:
|
elif chk >= 400 or chk is False:
|
||||||
# Problems connecting to server. Pick another server?
|
# Problems connecting to server. Pick another server?
|
||||||
resp = dialog.yesno(self.addonName,
|
resp = dialog.yesno(self.addonName,
|
||||||
string(39015).encode('utf-8'))
|
string(39015))
|
||||||
# Exit while loop if user chooses No
|
# Exit while loop if user chooses No
|
||||||
if not resp:
|
if not resp:
|
||||||
break
|
break
|
||||||
|
@ -171,18 +171,21 @@ class InitialSetup():
|
||||||
break
|
break
|
||||||
if not isconnected:
|
if not isconnected:
|
||||||
# Enter Kodi settings instead
|
# Enter Kodi settings instead
|
||||||
if dialog.yesno(
|
|
||||||
heading=self.addonName,
|
|
||||||
line1=string(39016).encode('utf-8')):
|
|
||||||
self.logMsg("User opted to disable Plex music library.", 1)
|
|
||||||
utils.settings('enableMusic', value="false")
|
|
||||||
xbmc.executebuiltin('Addon.OpenSettings(%s)' % self.addonId)
|
xbmc.executebuiltin('Addon.OpenSettings(%s)' % self.addonId)
|
||||||
return
|
return
|
||||||
# Write to Kodi settings file
|
# Write to Kodi settings file
|
||||||
utils.settings('plex_machineIdentifier', activeServer)
|
utils.settings('plex_machineIdentifier', activeServer)
|
||||||
utils.settings('ipaddress', server['ip'])
|
if server['local'] == '1':
|
||||||
utils.settings('port', server['port'])
|
scheme = server['scheme']
|
||||||
if server['scheme'] == 'https':
|
utils.settings('ipaddress', server['ip'])
|
||||||
|
utils.settings('port', server['port'])
|
||||||
|
else:
|
||||||
|
baseURL = server['baseURL'].split(':')
|
||||||
|
scheme = baseURL[0]
|
||||||
|
utils.settings('ipaddress', baseURL[1].replace('//', ''))
|
||||||
|
utils.settings('port', baseURL[2])
|
||||||
|
|
||||||
|
if scheme == 'https':
|
||||||
utils.settings('https', 'true')
|
utils.settings('https', 'true')
|
||||||
else:
|
else:
|
||||||
utils.settings('https', 'false')
|
utils.settings('https', 'false')
|
||||||
|
@ -207,14 +210,14 @@ class InitialSetup():
|
||||||
if forcePlexTV:
|
if forcePlexTV:
|
||||||
return
|
return
|
||||||
|
|
||||||
if dialog.yesno(
|
# Disable Plex music?
|
||||||
heading=self.addonName,
|
if dialog.yesno(heading=self.addonName,
|
||||||
line1=string(39016).encode('utf-8')):
|
line1=string(39016)):
|
||||||
self.logMsg("User opted to disable Plex music library.", 1)
|
self.logMsg("User opted to disable Plex music library.", 1)
|
||||||
utils.settings('enableMusic', value="false")
|
utils.settings('enableMusic', value="false")
|
||||||
|
|
||||||
if dialog.yesno(
|
# Open Settings page now?
|
||||||
heading=self.addonName,
|
if dialog.yesno(heading=self.addonName,
|
||||||
line1=string(39017).encode('utf-8')):
|
line1=string(39017)):
|
||||||
xbmc.executebuiltin(
|
xbmc.executebuiltin(
|
||||||
'Addon.OpenSettings(plugin.video.plexkodiconnect)')
|
'Addon.OpenSettings(plugin.video.plexkodiconnect)')
|
||||||
|
|
|
@ -8,6 +8,7 @@ import Queue
|
||||||
import xbmc
|
import xbmc
|
||||||
import xbmcgui
|
import xbmcgui
|
||||||
import xbmcvfs
|
import xbmcvfs
|
||||||
|
import xbmcaddon
|
||||||
|
|
||||||
import utils
|
import utils
|
||||||
import clientinfo
|
import clientinfo
|
||||||
|
@ -24,6 +25,7 @@ import PlexFunctions
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
|
|
||||||
|
@utils.logging
|
||||||
@utils.ThreadMethodsAdditionalStop('emby_shouldStop')
|
@utils.ThreadMethodsAdditionalStop('emby_shouldStop')
|
||||||
@utils.ThreadMethods
|
@utils.ThreadMethods
|
||||||
class ThreadedGetMetadata(Thread):
|
class ThreadedGetMetadata(Thread):
|
||||||
|
@ -38,10 +40,11 @@ class ThreadedGetMetadata(Thread):
|
||||||
the downloaded metadata XMLs as etree objects
|
the downloaded metadata XMLs as etree objects
|
||||||
lock Lock(), used for counting where we are
|
lock Lock(), used for counting where we are
|
||||||
"""
|
"""
|
||||||
def __init__(self, queue, out_queue, lock):
|
def __init__(self, queue, out_queue, lock, processlock):
|
||||||
self.queue = queue
|
self.queue = queue
|
||||||
self.out_queue = out_queue
|
self.out_queue = out_queue
|
||||||
self.lock = lock
|
self.lock = lock
|
||||||
|
self.processlock = processlock
|
||||||
Thread.__init__(self)
|
Thread.__init__(self)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
@ -49,8 +52,10 @@ class ThreadedGetMetadata(Thread):
|
||||||
queue = self.queue
|
queue = self.queue
|
||||||
out_queue = self.out_queue
|
out_queue = self.out_queue
|
||||||
lock = self.lock
|
lock = self.lock
|
||||||
|
processlock = self.processlock
|
||||||
threadStopped = self.threadStopped
|
threadStopped = self.threadStopped
|
||||||
global getMetadataCount
|
global getMetadataCount
|
||||||
|
global processMetadataCount
|
||||||
while threadStopped() is False:
|
while threadStopped() is False:
|
||||||
# grabs Plex item from queue
|
# grabs Plex item from queue
|
||||||
try:
|
try:
|
||||||
|
@ -63,6 +68,14 @@ class ThreadedGetMetadata(Thread):
|
||||||
plexXML = PlexFunctions.GetPlexMetadata(updateItem['itemId'])
|
plexXML = PlexFunctions.GetPlexMetadata(updateItem['itemId'])
|
||||||
if plexXML is None:
|
if plexXML is None:
|
||||||
# Did not receive a valid XML - skip that item for now
|
# Did not receive a valid XML - skip that item for now
|
||||||
|
self.logMsg("Could not get metadata for %s. "
|
||||||
|
"Skipping that item for now"
|
||||||
|
% updateItem['itemId'], -1)
|
||||||
|
# Increase BOTH counters - since metadata won't be processed
|
||||||
|
with lock:
|
||||||
|
getMetadataCount += 1
|
||||||
|
with processlock:
|
||||||
|
processMetadataCount += 1
|
||||||
queue.task_done()
|
queue.task_done()
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -113,25 +126,20 @@ class ThreadedProcessMetadata(Thread):
|
||||||
except Queue.Empty:
|
except Queue.Empty:
|
||||||
xbmc.sleep(100)
|
xbmc.sleep(100)
|
||||||
continue
|
continue
|
||||||
# Do the work; lock to be sure we've only got 1 Thread
|
# Do the work
|
||||||
plexitem = updateItem['XML']
|
plexitem = updateItem['XML']
|
||||||
method = updateItem['method']
|
method = updateItem['method']
|
||||||
viewName = updateItem['viewName']
|
viewName = updateItem['viewName']
|
||||||
viewId = updateItem['viewId']
|
viewId = updateItem['viewId']
|
||||||
title = updateItem['title']
|
title = updateItem['title']
|
||||||
itemSubFkt = getattr(item, method)
|
itemSubFkt = getattr(item, method)
|
||||||
|
# Get the one child entry in the xml and process
|
||||||
|
for child in plexitem:
|
||||||
|
itemSubFkt(child,
|
||||||
|
viewtag=viewName,
|
||||||
|
viewid=viewId)
|
||||||
|
# Keep track of where we are at
|
||||||
with lock:
|
with lock:
|
||||||
# Get the one child entry in the xml and process
|
|
||||||
for child in plexitem:
|
|
||||||
if method == 'add_updateAlbum':
|
|
||||||
item.add_updateAlbum(child,
|
|
||||||
viewtag=viewName,
|
|
||||||
viewid=viewId)
|
|
||||||
else:
|
|
||||||
itemSubFkt(child,
|
|
||||||
viewtag=viewName,
|
|
||||||
viewid=viewId)
|
|
||||||
# Keep track of where we are at
|
|
||||||
processMetadataCount += 1
|
processMetadataCount += 1
|
||||||
processingViewName = title
|
processingViewName = title
|
||||||
# signals to queue job is done
|
# signals to queue job is done
|
||||||
|
@ -164,10 +172,10 @@ class ThreadedShowSyncInfo(Thread):
|
||||||
threadStopped = self.threadStopped
|
threadStopped = self.threadStopped
|
||||||
downloadLock = self.locks[0]
|
downloadLock = self.locks[0]
|
||||||
processLock = self.locks[1]
|
processLock = self.locks[1]
|
||||||
dialog.create(("%s: Sync %s: %s items"
|
dialog.create("%s: Sync %s: %s items"
|
||||||
% (self.addonName,
|
% (self.addonName,
|
||||||
self.itemType,
|
self.itemType,
|
||||||
str(total))).encode('utf-8'),
|
str(total)),
|
||||||
"Starting")
|
"Starting")
|
||||||
global getMetadataCount
|
global getMetadataCount
|
||||||
global processMetadataCount
|
global processMetadataCount
|
||||||
|
@ -185,15 +193,11 @@ class ThreadedShowSyncInfo(Thread):
|
||||||
percentage = int(float(totalProgress) / float(total)*100.0)
|
percentage = int(float(totalProgress) / float(total)*100.0)
|
||||||
except ZeroDivisionError:
|
except ZeroDivisionError:
|
||||||
percentage = 0
|
percentage = 0
|
||||||
try:
|
dialog.update(percentage,
|
||||||
dialog.update(
|
message="Downloaded: %s. Processed: %s: %s"
|
||||||
percentage,
|
% (getMetadataProgress,
|
||||||
message=("Downloaded: %s. Processed: %s: %s"
|
processMetadataProgress,
|
||||||
% (getMetadataProgress, processMetadataProgress,
|
viewName))
|
||||||
viewName))).encode('utf-8')
|
|
||||||
except:
|
|
||||||
# Wierd formating of the string viewName?!?
|
|
||||||
pass
|
|
||||||
# Sleep for x milliseconds
|
# Sleep for x milliseconds
|
||||||
xbmc.sleep(500)
|
xbmc.sleep(500)
|
||||||
dialog.close()
|
dialog.close()
|
||||||
|
@ -213,6 +217,8 @@ class LibrarySync(Thread):
|
||||||
|
|
||||||
self.__dict__ = self._shared_state
|
self.__dict__ = self._shared_state
|
||||||
|
|
||||||
|
self.__language__ = xbmcaddon.Addon().getLocalizedString
|
||||||
|
|
||||||
self.clientInfo = clientinfo.ClientInfo()
|
self.clientInfo = clientinfo.ClientInfo()
|
||||||
self.user = userclient.UserClient()
|
self.user = userclient.UserClient()
|
||||||
self.emby = embyserver.Read_EmbyServer()
|
self.emby = embyserver.Read_EmbyServer()
|
||||||
|
@ -226,33 +232,23 @@ class LibrarySync(Thread):
|
||||||
self.enableMusic = True if utils.settings('enableMusic') == "true" \
|
self.enableMusic = True if utils.settings('enableMusic') == "true" \
|
||||||
else False
|
else False
|
||||||
self.enableBackgroundSync = True if utils.settings(
|
self.enableBackgroundSync = True if utils.settings(
|
||||||
'enableBackgroundSync') == "true" \
|
'enableBackgroundSync') == "true" else False
|
||||||
else False
|
|
||||||
|
|
||||||
Thread.__init__(self)
|
Thread.__init__(self)
|
||||||
|
|
||||||
def showKodiNote(self, message, forced=False):
|
def showKodiNote(self, message, forced=False):
|
||||||
"""
|
"""
|
||||||
Shows a Kodi popup, if user selected to do so
|
Shows a Kodi popup, if user selected to do so. Pass message in unicode
|
||||||
|
or string
|
||||||
"""
|
"""
|
||||||
if not (self.showDbSync or forced):
|
if not (self.showDbSync or forced):
|
||||||
return
|
return
|
||||||
xbmcgui.Dialog().notification(
|
xbmcgui.Dialog().notification(
|
||||||
heading=self.addonName,
|
heading=self.addonName,
|
||||||
message=message.encode('utf-8'),
|
message=message,
|
||||||
icon="special://home/addons/plugin.video.plexkodiconnect/icon.png",
|
icon="special://home/addons/plugin.video.plexkodiconnect/icon.png",
|
||||||
sound=False)
|
sound=False)
|
||||||
|
|
||||||
def startSync(self):
|
|
||||||
utils.window('emby_dbScan', value="true")
|
|
||||||
completed = self.fastSync()
|
|
||||||
if not completed:
|
|
||||||
# Fast sync failed or server plugin is not found
|
|
||||||
self.logMsg("Something went wrong, starting full sync", -1)
|
|
||||||
completed = self.fullSync(manualrun=True)
|
|
||||||
utils.window('emby_dbScan', clear=True)
|
|
||||||
return completed
|
|
||||||
|
|
||||||
def fastSync(self):
|
def fastSync(self):
|
||||||
"""
|
"""
|
||||||
Fast incremential lib sync
|
Fast incremential lib sync
|
||||||
|
@ -291,8 +287,8 @@ class LibrarySync(Thread):
|
||||||
if self.threadStopped():
|
if self.threadStopped():
|
||||||
return True
|
return True
|
||||||
# Get items per view
|
# Get items per view
|
||||||
items = PlexFunctions.GetAllPlexLeaves(
|
items = PlexFunctions.GetAllPlexLeaves(view['id'],
|
||||||
view['id'], updatedAt=lastSync)
|
updatedAt=lastSync)
|
||||||
# Just skip item if something went wrong
|
# Just skip item if something went wrong
|
||||||
if not items:
|
if not items:
|
||||||
continue
|
continue
|
||||||
|
@ -456,7 +452,7 @@ class LibrarySync(Thread):
|
||||||
"Found viewid: %s" % folderid,
|
"Found viewid: %s" % folderid,
|
||||||
"viewname: %s" % current_viewname,
|
"viewname: %s" % current_viewname,
|
||||||
"viewtype: %s" % current_viewtype,
|
"viewtype: %s" % current_viewtype,
|
||||||
"tagid: %s" % current_tagid)), 2)
|
"tagid: %s" % current_tagid)), 1)
|
||||||
|
|
||||||
# Remove views that are still valid to delete rest later
|
# Remove views that are still valid to delete rest later
|
||||||
try:
|
try:
|
||||||
|
@ -739,7 +735,8 @@ class LibrarySync(Thread):
|
||||||
for i in range(min(self.syncThreadNumber, itemNumber)):
|
for i in range(min(self.syncThreadNumber, itemNumber)):
|
||||||
thread = ThreadedGetMetadata(getMetadataQueue,
|
thread = ThreadedGetMetadata(getMetadataQueue,
|
||||||
processMetadataQueue,
|
processMetadataQueue,
|
||||||
getMetadataLock)
|
getMetadataLock,
|
||||||
|
processMetadataLock)
|
||||||
thread.setDaemon(True)
|
thread.setDaemon(True)
|
||||||
thread.start()
|
thread.start()
|
||||||
threads.append(thread)
|
threads.append(thread)
|
||||||
|
@ -1121,37 +1118,46 @@ class LibrarySync(Thread):
|
||||||
self.run_internal()
|
self.run_internal()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
utils.window('emby_dbScan', clear=True)
|
utils.window('emby_dbScan', clear=True)
|
||||||
|
self.logMsg('LibrarySync thread crashed', -1)
|
||||||
|
# Library sync thread has crashed
|
||||||
xbmcgui.Dialog().ok(
|
xbmcgui.Dialog().ok(
|
||||||
heading=self.addonName,
|
heading=self.addonName,
|
||||||
line1=("Library sync thread has crashed. "
|
line1=self.__language__(39400))
|
||||||
"You should restart Kodi now. "
|
|
||||||
"Please report this on the forum."))
|
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def run_internal(self):
|
def run_internal(self):
|
||||||
|
# Re-assign handles to have faster calls
|
||||||
window = utils.window
|
window = utils.window
|
||||||
settings = utils.settings
|
settings = utils.settings
|
||||||
log = self.logMsg
|
log = self.logMsg
|
||||||
|
threadStopped = self.threadStopped
|
||||||
|
threadSuspended = self.threadSuspended
|
||||||
|
installSyncDone = self.installSyncDone
|
||||||
|
enableBackgroundSync = self.enableBackgroundSync
|
||||||
|
fullSync = self.fullSync
|
||||||
|
fastSync = self.fastSync
|
||||||
|
string = self.__language__
|
||||||
|
|
||||||
|
dialog = xbmcgui.Dialog()
|
||||||
|
|
||||||
startupComplete = False
|
startupComplete = False
|
||||||
self.views = []
|
self.views = []
|
||||||
count = 0
|
count = 0
|
||||||
errorcount = 0
|
errorcount = 0
|
||||||
|
|
||||||
self.logMsg("---===### Starting LibrarySync ###===---", 0)
|
log("---===### Starting LibrarySync ###===---", 0)
|
||||||
while not self.threadStopped():
|
while not threadStopped():
|
||||||
|
|
||||||
# In the event the server goes offline, or an item is playing
|
# In the event the server goes offline, or an item is playing
|
||||||
while self.threadSuspended():
|
while threadSuspended():
|
||||||
# Set in service.py
|
# Set in service.py
|
||||||
if self.threadStopped():
|
if threadStopped():
|
||||||
# Abort was requested while waiting. We should exit
|
# Abort was requested while waiting. We should exit
|
||||||
log("###===--- LibrarySync Stopped ---===###", 0)
|
log("###===--- LibrarySync Stopped ---===###", 0)
|
||||||
return
|
return
|
||||||
xbmc.sleep(1000)
|
xbmc.sleep(1000)
|
||||||
|
|
||||||
if (window('emby_dbCheck') != "true" and
|
if (window('emby_dbCheck') != "true" and installSyncDone):
|
||||||
self.installSyncDone):
|
|
||||||
# Verify the validity of the database
|
# Verify the validity of the database
|
||||||
currentVersion = settings('dbCreatedWithVersion')
|
currentVersion = settings('dbCreatedWithVersion')
|
||||||
minVersion = window('emby_minDBVersion')
|
minVersion = window('emby_minDBVersion')
|
||||||
|
@ -1160,17 +1166,14 @@ class LibrarySync(Thread):
|
||||||
if not uptoDate:
|
if not uptoDate:
|
||||||
log("Db version out of date: %s minimum version required: "
|
log("Db version out of date: %s minimum version required: "
|
||||||
"%s" % (currentVersion, minVersion), 0)
|
"%s" % (currentVersion, minVersion), 0)
|
||||||
resp = xbmcgui.Dialog().yesno(
|
# DB out of date. Proceed to recreate?
|
||||||
heading="Db Version",
|
resp = dialog.yesno(heading=self.addonName,
|
||||||
line1=("Detected the database needs to be recreated "
|
line1=string(39401))
|
||||||
"for this version of " + self.addonName +
|
|
||||||
"Proceed?"))
|
|
||||||
if not resp:
|
if not resp:
|
||||||
log("Db version out of date! USER IGNORED!", 0)
|
log("Db version out of date! USER IGNORED!", 0)
|
||||||
xbmcgui.Dialog().ok(
|
# PKC may not work correctly until reset
|
||||||
heading=self.addonName,
|
dialog.ok(heading=self.addonName,
|
||||||
line1=(self.addonName + " may not work correctly "
|
line1=(self.addonName + string(39402)))
|
||||||
"until the database is reset."))
|
|
||||||
else:
|
else:
|
||||||
utils.reset()
|
utils.reset()
|
||||||
break
|
break
|
||||||
|
@ -1184,20 +1187,19 @@ class LibrarySync(Thread):
|
||||||
if not xbmcvfs.exists(videoDb):
|
if not xbmcvfs.exists(videoDb):
|
||||||
# Database does not exists
|
# Database does not exists
|
||||||
log("The current Kodi version is incompatible "
|
log("The current Kodi version is incompatible "
|
||||||
"to know which Kodi versions are supported.", 0)
|
"to know which Kodi versions are supported.", -1)
|
||||||
xbmcgui.Dialog().ok(
|
log('Current Kodi version: %s' % xbmc.getInfoLabel(
|
||||||
heading=self.addonName,
|
'System.BuildVersion').decode('utf-8'))
|
||||||
line1=("Cancelling the database syncing process. "
|
# "Current Kodi version is unsupported, cancel lib sync"
|
||||||
"Current Kodi version: %s is unsupported. "
|
dialog.ok(heading=self.addonName,
|
||||||
"Please verify your logs for more info."
|
line1=string(39403))
|
||||||
% xbmc.getInfoLabel('System.BuildVersion')))
|
|
||||||
break
|
break
|
||||||
|
|
||||||
# Run start up sync
|
# Run start up sync
|
||||||
window('emby_dbScan', value="true")
|
window('emby_dbScan', value="true")
|
||||||
log("Db version: %s" % settings('dbCreatedWithVersion'), 0)
|
log("Db version: %s" % settings('dbCreatedWithVersion'), 0)
|
||||||
log("Initial start-up full sync starting", 0)
|
log("Initial start-up full sync starting", 0)
|
||||||
librarySync = self.fullSync(manualrun=True)
|
librarySync = fullSync(manualrun=True)
|
||||||
window('emby_dbScan', clear=True)
|
window('emby_dbScan', clear=True)
|
||||||
if librarySync:
|
if librarySync:
|
||||||
log("Initial start-up full sync successful", 0)
|
log("Initial start-up full sync successful", 0)
|
||||||
|
@ -1205,17 +1207,16 @@ class LibrarySync(Thread):
|
||||||
settings('SyncInstallRunDone', value="true")
|
settings('SyncInstallRunDone', value="true")
|
||||||
settings("dbCreatedWithVersion",
|
settings("dbCreatedWithVersion",
|
||||||
self.clientInfo.getVersion())
|
self.clientInfo.getVersion())
|
||||||
self.installSyncDone = True
|
installSyncDone = True
|
||||||
else:
|
else:
|
||||||
log("Initial start-up full sync unsuccessful", -1)
|
log("Initial start-up full sync unsuccessful", -1)
|
||||||
errorcount += 1
|
errorcount += 1
|
||||||
if errorcount > 2:
|
if errorcount > 2:
|
||||||
log("Startup full sync failed. Stopping sync", -1)
|
log("Startup full sync failed. Stopping sync", -1)
|
||||||
xbmcgui.Dialog().ok(
|
# "Startup syncing process failed repeatedly"
|
||||||
heading=self.addonName,
|
# "Please restart"
|
||||||
line1=("Startup syncing process failed repeatedly."
|
dialog.ok(heading=self.addonName,
|
||||||
" Try restarting Kodi. Stopping Sync for "
|
line1=string(39404))
|
||||||
"now."))
|
|
||||||
break
|
break
|
||||||
|
|
||||||
# Currently no db scan, so we can start a new scan
|
# Currently no db scan, so we can start a new scan
|
||||||
|
@ -1225,7 +1226,7 @@ class LibrarySync(Thread):
|
||||||
log('Full library scan requested, starting', 0)
|
log('Full library scan requested, starting', 0)
|
||||||
window('emby_dbScan', value="true")
|
window('emby_dbScan', value="true")
|
||||||
window('plex_runLibScan', clear=True)
|
window('plex_runLibScan', clear=True)
|
||||||
self.fullSync(manualrun=True)
|
fullSync(manualrun=True)
|
||||||
window('emby_dbScan', clear=True)
|
window('emby_dbScan', clear=True)
|
||||||
count = 0
|
count = 0
|
||||||
# Reset views was requested from somewhere else
|
# Reset views was requested from somewhere else
|
||||||
|
@ -1239,36 +1240,45 @@ class LibrarySync(Thread):
|
||||||
# Remove video nodes
|
# Remove video nodes
|
||||||
utils.deleteNodes()
|
utils.deleteNodes()
|
||||||
# Kick off refresh
|
# Kick off refresh
|
||||||
dialog = xbmcgui.Dialog()
|
|
||||||
if self.maintainViews():
|
if self.maintainViews():
|
||||||
|
# Ran successfully
|
||||||
|
log("Refresh playlists/nodes completed", 0)
|
||||||
|
# "Plex playlists/nodes refreshed"
|
||||||
dialog.notification(
|
dialog.notification(
|
||||||
heading=self.addonName,
|
heading=self.addonName,
|
||||||
message="Plex playlists/nodes refreshed",
|
message=string(39405),
|
||||||
icon="special://home/addons/plugin.video.plexkodiconnect/icon.png",
|
icon="special://home/addons/plugin.video.plexkodiconnect/icon.png",
|
||||||
time=3000,
|
time=3000,
|
||||||
sound=True)
|
sound=True)
|
||||||
else:
|
else:
|
||||||
self.logMsg("Refresh playlists/nodes failed", -1)
|
# Failed
|
||||||
|
log("Refresh playlists/nodes failed", -1)
|
||||||
|
# "Plex playlists/nodes refresh failed"
|
||||||
dialog.notification(
|
dialog.notification(
|
||||||
heading=self.addonName,
|
heading=self.addonName,
|
||||||
message="Plex playlists/nodes refresh failed",
|
message=string(39406),
|
||||||
icon=xbmcgui.NOTIFICATION_ERROR,
|
icon=xbmcgui.NOTIFICATION_ERROR,
|
||||||
time=3000,
|
time=3000,
|
||||||
sound=True)
|
sound=True)
|
||||||
window('emby_dbScan', clear=True)
|
window('emby_dbScan', clear=True)
|
||||||
elif self.enableBackgroundSync:
|
elif enableBackgroundSync:
|
||||||
# Run full lib scan approx every 30min
|
# Run full lib scan approx every 30min
|
||||||
if count >= 1800:
|
if count >= 1800:
|
||||||
count = 0
|
count = 0
|
||||||
window('emby_dbScan', value="true")
|
window('emby_dbScan', value="true")
|
||||||
log('Running automatic full lib scan', 0)
|
log('Running background full lib scan', 0)
|
||||||
self.fullSync(manualrun=True)
|
fullSync(manualrun=True)
|
||||||
window('emby_dbScan', clear=True)
|
window('emby_dbScan', clear=True)
|
||||||
# Run fast sync otherwise (ever 2 seconds or so)
|
# Run fast sync otherwise (ever second or so)
|
||||||
else:
|
else:
|
||||||
self.startSync()
|
window('emby_dbScan', value="true")
|
||||||
|
if not fastSync():
|
||||||
|
# Fast sync failed or server plugin is not found
|
||||||
|
log("Something went wrong, starting full sync", -1)
|
||||||
|
fullSync(manualrun=True)
|
||||||
|
window('emby_dbScan', clear=True)
|
||||||
|
|
||||||
xbmc.sleep(2000)
|
xbmc.sleep(1000)
|
||||||
count += 1
|
count += 1
|
||||||
|
|
||||||
log("###===--- LibrarySync Stopped ---===###", 0)
|
log("###===--- LibrarySync Stopped ---===###", 0)
|
||||||
|
|
|
@ -524,8 +524,8 @@ class Player(xbmc.Player):
|
||||||
offerDelete = False
|
offerDelete = False
|
||||||
if percentComplete >= markPlayedAt and offerDelete:
|
if percentComplete >= markPlayedAt and offerDelete:
|
||||||
resp = xbmcgui.Dialog().yesno(
|
resp = xbmcgui.Dialog().yesno(
|
||||||
lang(30091).encode('utf-8'),
|
lang(30091),
|
||||||
lang(33015).encode('utf-8'),
|
lang(33015),
|
||||||
autoclose=120000)
|
autoclose=120000)
|
||||||
if not resp:
|
if not resp:
|
||||||
log("User skipped deletion.", 1)
|
log("User skipped deletion.", 1)
|
||||||
|
|
|
@ -34,6 +34,8 @@ class PlayUtils():
|
||||||
"""
|
"""
|
||||||
Returns the playurl for the part with number partNumber
|
Returns the playurl for the part with number partNumber
|
||||||
(movie might consist of several files)
|
(movie might consist of several files)
|
||||||
|
|
||||||
|
playurl is utf-8 encoded!
|
||||||
"""
|
"""
|
||||||
log = self.logMsg
|
log = self.logMsg
|
||||||
window = utils.window
|
window = utils.window
|
||||||
|
@ -64,6 +66,7 @@ class PlayUtils():
|
||||||
}
|
}
|
||||||
playurl = self.API.getTranscodeVideoPath('Transcode',
|
playurl = self.API.getTranscodeVideoPath('Transcode',
|
||||||
quality=quality)
|
quality=quality)
|
||||||
|
playurl = playurl.encode('utf-8')
|
||||||
# Set playmethod property
|
# Set playmethod property
|
||||||
window('emby_%s.playmethod' % playurl, value="Transcode")
|
window('emby_%s.playmethod' % playurl, value="Transcode")
|
||||||
|
|
||||||
|
@ -371,7 +374,7 @@ class PlayUtils():
|
||||||
subNum += 1
|
subNum += 1
|
||||||
|
|
||||||
if audioNum > 1:
|
if audioNum > 1:
|
||||||
resp = dialog.select(lang(33013).encode('utf-8'), audioStreams)
|
resp = dialog.select(lang(33013), audioStreams)
|
||||||
if resp > -1:
|
if resp > -1:
|
||||||
# User selected audio
|
# User selected audio
|
||||||
playurlprefs['audioStreamID'] = audioStreamsList[resp]
|
playurlprefs['audioStreamID'] = audioStreamsList[resp]
|
||||||
|
@ -384,7 +387,7 @@ class PlayUtils():
|
||||||
playurlprefs['audioBoost'] = utils.settings('audioBoost')
|
playurlprefs['audioBoost'] = utils.settings('audioBoost')
|
||||||
|
|
||||||
if subNum > 1:
|
if subNum > 1:
|
||||||
resp = dialog.select(lang(33014).encode('utf-8'), subtitleStreams)
|
resp = dialog.select(lang(33014), subtitleStreams)
|
||||||
if resp == 0:
|
if resp == 0:
|
||||||
# User selected no subtitles
|
# User selected no subtitles
|
||||||
playurlprefs["skipSubtitles"] = 1
|
playurlprefs["skipSubtitles"] = 1
|
||||||
|
|
|
@ -31,7 +31,10 @@ import re
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
import urllib2
|
import urllib2
|
||||||
|
|
||||||
import downloadutils
|
import downloadutils
|
||||||
|
from PlexFunctions import PMSHttpsEnabled
|
||||||
|
|
||||||
|
|
||||||
class plexgdm:
|
class plexgdm:
|
||||||
|
|
||||||
|
@ -56,6 +59,7 @@ class plexgdm:
|
||||||
self.discovery_complete = False
|
self.discovery_complete = False
|
||||||
self.client_registered = False
|
self.client_registered = False
|
||||||
self.debug = debug
|
self.debug = debug
|
||||||
|
self.download = downloadutils.DownloadUtils().downloadUrl
|
||||||
|
|
||||||
def __printDebug(self, message, level=1):
|
def __printDebug(self, message, level=1):
|
||||||
if self.debug:
|
if self.debug:
|
||||||
|
@ -139,13 +143,19 @@ class plexgdm:
|
||||||
try:
|
try:
|
||||||
media_server=self.server_list[0]['server']
|
media_server=self.server_list[0]['server']
|
||||||
media_port=self.server_list[0]['port']
|
media_port=self.server_list[0]['port']
|
||||||
|
scheme = self.server_list[0]['protocol']
|
||||||
|
|
||||||
self.__printDebug("Checking server [%s] on port [%s]" % (media_server, media_port) ,2)
|
self.__printDebug("Checking server [%s] on port [%s]" % (media_server, media_port) ,2)
|
||||||
client_result = downloadutils.DownloadUtils().downloadUrl(
|
client_result = self.download(
|
||||||
'http://%s:%s/clients' % (media_server, media_port))
|
'%s://%s:%s/clients' % (scheme, media_server, media_port))
|
||||||
# f = urllib2.urlopen('http://%s:%s/clients' % (media_server, media_port))
|
# f = urllib2.urlopen('http://%s:%s/clients' % (media_server, media_port))
|
||||||
# client_result = f.read()
|
# client_result = f.read()
|
||||||
if self.client_id in str(client_result):
|
registered = False
|
||||||
|
for client in client_result:
|
||||||
|
if (client.attrib.get('machineIdentifier') ==
|
||||||
|
self.client_id):
|
||||||
|
registered = True
|
||||||
|
if registered:
|
||||||
self.__printDebug("Client registration successful",1)
|
self.__printDebug("Client registration successful",1)
|
||||||
self.__printDebug("Client data is: %s" % client_result, 3)
|
self.__printDebug("Client data is: %s" % client_result, 3)
|
||||||
return True
|
return True
|
||||||
|
@ -208,7 +218,6 @@ class plexgdm:
|
||||||
if "200 OK" in response.get('data'):
|
if "200 OK" in response.get('data'):
|
||||||
|
|
||||||
for each in response.get('data').split('\r\n'):
|
for each in response.get('data').split('\r\n'):
|
||||||
|
|
||||||
update['discovery'] = "auto"
|
update['discovery'] = "auto"
|
||||||
update['owned']='1'
|
update['owned']='1'
|
||||||
update['master']= 1
|
update['master']= 1
|
||||||
|
@ -230,6 +239,12 @@ class plexgdm:
|
||||||
elif "Server-Class:" in each:
|
elif "Server-Class:" in each:
|
||||||
update['class'] = each.split(':')[1].strip()
|
update['class'] = each.split(':')[1].strip()
|
||||||
|
|
||||||
|
# Quickly test if we need https
|
||||||
|
if PMSHttpsEnabled(
|
||||||
|
'%s:%s' % (update['server'], update['port'])):
|
||||||
|
update['protocol'] = 'https'
|
||||||
|
else:
|
||||||
|
update['protocol'] = 'http'
|
||||||
discovered_servers.append(update)
|
discovered_servers.append(update)
|
||||||
|
|
||||||
self.server_list = discovered_servers
|
self.server_list = discovered_servers
|
||||||
|
@ -239,7 +254,7 @@ class plexgdm:
|
||||||
else:
|
else:
|
||||||
self.__printDebug("Number of servers Discovered: %s" % len(self.server_list),1)
|
self.__printDebug("Number of servers Discovered: %s" % len(self.server_list),1)
|
||||||
for items in self.server_list:
|
for items in self.server_list:
|
||||||
self.__printDebug("Server Discovered: %s" % items['serverName'] ,2)
|
self.__printDebug("Server Discovered: %s" % items, 2)
|
||||||
|
|
||||||
|
|
||||||
def setInterval(self, interval):
|
def setInterval(self, interval):
|
||||||
|
|
|
@ -46,23 +46,16 @@ class UserClient(threading.Thread):
|
||||||
|
|
||||||
threading.Thread.__init__(self)
|
threading.Thread.__init__(self)
|
||||||
|
|
||||||
def getAdditionalUsers(self):
|
|
||||||
|
|
||||||
additionalUsers = utils.settings('additionalUsers')
|
|
||||||
|
|
||||||
if additionalUsers:
|
|
||||||
self.AdditionalUser = additionalUsers.split(',')
|
|
||||||
|
|
||||||
def getUsername(self):
|
def getUsername(self):
|
||||||
"""
|
"""
|
||||||
Returns username as unicode
|
Returns username as unicode
|
||||||
"""
|
"""
|
||||||
|
|
||||||
username = utils.settings('username').decode('utf-8')
|
username = utils.settings('username')
|
||||||
|
|
||||||
if not username:
|
if not username:
|
||||||
self.logMsg("No username saved, trying to get Plex username", 0)
|
self.logMsg("No username saved, trying to get Plex username", 0)
|
||||||
username = utils.settings('plexLogin').decode('utf-8')
|
username = utils.settings('plexLogin')
|
||||||
if not username:
|
if not username:
|
||||||
self.logMsg("Also no Plex username found", 0)
|
self.logMsg("Also no Plex username found", 0)
|
||||||
return ""
|
return ""
|
||||||
|
@ -245,9 +238,8 @@ class UserClient(threading.Thread):
|
||||||
log("Access is granted.", 1)
|
log("Access is granted.", 1)
|
||||||
self.HasAccess = True
|
self.HasAccess = True
|
||||||
window('emby_serverStatus', clear=True)
|
window('emby_serverStatus', clear=True)
|
||||||
xbmcgui.Dialog().notification(
|
xbmcgui.Dialog().notification(self.addonName,
|
||||||
self.addonName,
|
utils.language(33007))
|
||||||
utils.language(33007).encode('utf-8'))
|
|
||||||
|
|
||||||
def loadCurrUser(self, authenticated=False):
|
def loadCurrUser(self, authenticated=False):
|
||||||
self.logMsg('Loading current user', 0)
|
self.logMsg('Loading current user', 0)
|
||||||
|
@ -318,7 +310,8 @@ class UserClient(threading.Thread):
|
||||||
dialog = xbmcgui.Dialog()
|
dialog = xbmcgui.Dialog()
|
||||||
|
|
||||||
# Get /profile/addon_data
|
# Get /profile/addon_data
|
||||||
addondir = xbmc.translatePath(self.addon.getAddonInfo('profile')).decode('utf-8')
|
addondir = xbmc.translatePath(
|
||||||
|
self.addon.getAddonInfo('profile')).decode('utf-8')
|
||||||
hasSettings = xbmcvfs.exists("%ssettings.xml" % addondir)
|
hasSettings = xbmcvfs.exists("%ssettings.xml" % addondir)
|
||||||
|
|
||||||
# If there's no settings.xml
|
# If there's no settings.xml
|
||||||
|
@ -373,7 +366,7 @@ class UserClient(threading.Thread):
|
||||||
if username:
|
if username:
|
||||||
dialog.notification(
|
dialog.notification(
|
||||||
heading=self.addonName,
|
heading=self.addonName,
|
||||||
message=("Welcome " + username).encode('utf-8'),
|
message="Welcome " + username,
|
||||||
icon="special://home/addons/plugin.video.plexkodiconnect/icon.png")
|
icon="special://home/addons/plugin.video.plexkodiconnect/icon.png")
|
||||||
else:
|
else:
|
||||||
dialog.notification(
|
dialog.notification(
|
||||||
|
@ -388,11 +381,11 @@ class UserClient(threading.Thread):
|
||||||
settings('userId', value="")
|
settings('userId', value="")
|
||||||
|
|
||||||
# Give attempts at entering password / selecting user
|
# Give attempts at entering password / selecting user
|
||||||
if self.retry >= 5:
|
if self.retry >= 2:
|
||||||
log("Too many retries.", 1)
|
log("Too many retries to login.", -1)
|
||||||
window('emby_serverStatus', value="Stop")
|
window('emby_serverStatus', value="Stop")
|
||||||
dialog.ok(lang(33001).encode('utf-8'),
|
dialog.ok(lang(33001),
|
||||||
lang(39023).encode('utf-8'))
|
lang(39023))
|
||||||
xbmc.executebuiltin(
|
xbmc.executebuiltin(
|
||||||
'Addon.OpenSettings(plugin.video.plexkodiconnect)')
|
'Addon.OpenSettings(plugin.video.plexkodiconnect)')
|
||||||
|
|
||||||
|
@ -423,7 +416,7 @@ class UserClient(threading.Thread):
|
||||||
while self.threadSuspended():
|
while self.threadSuspended():
|
||||||
if self.threadStopped():
|
if self.threadStopped():
|
||||||
break
|
break
|
||||||
xbmc.sleep(3000)
|
xbmc.sleep(1000)
|
||||||
|
|
||||||
status = window('emby_serverStatus')
|
status = window('emby_serverStatus')
|
||||||
if status:
|
if status:
|
||||||
|
@ -455,5 +448,8 @@ class UserClient(threading.Thread):
|
||||||
log("Server found: %s" % server, 2)
|
log("Server found: %s" % server, 2)
|
||||||
self.auth = True
|
self.auth = True
|
||||||
|
|
||||||
|
# Minimize CPU load
|
||||||
|
xbmc.sleep(500)
|
||||||
|
|
||||||
self.doUtils.stopSession()
|
self.doUtils.stopSession()
|
||||||
log("##===---- UserClient Stopped ----===##", 0)
|
log("##===---- UserClient Stopped ----===##", 0)
|
||||||
|
|
|
@ -192,32 +192,47 @@ def logMsg(title, msg, level=1):
|
||||||
logLevel = int(window('emby_logLevel'))
|
logLevel = int(window('emby_logLevel'))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
logLevel = 0
|
logLevel = 0
|
||||||
|
kodiLevel = {
|
||||||
|
-1: xbmc.LOGERROR,
|
||||||
|
0: xbmc.LOGNOTICE,
|
||||||
|
1: xbmc.LOGNOTICE,
|
||||||
|
2: xbmc.LOGNOTICE
|
||||||
|
}
|
||||||
if logLevel >= level:
|
if logLevel >= level:
|
||||||
|
|
||||||
if logLevel == 2: # inspect is expensive
|
if logLevel == 2: # inspect is expensive
|
||||||
func = inspect.currentframe().f_back.f_back.f_code
|
func = inspect.currentframe().f_back.f_back.f_code
|
||||||
try:
|
try:
|
||||||
xbmc.log("%s -> %s : %s" % (
|
xbmc.log("%s -> %s : %s" % (
|
||||||
title, func.co_name, msg))
|
title, func.co_name, msg), level=kodiLevel[level])
|
||||||
except UnicodeEncodeError:
|
except UnicodeEncodeError:
|
||||||
try:
|
try:
|
||||||
xbmc.log("%s -> %s : %s" % (
|
xbmc.log("%s -> %s : %s" % (
|
||||||
title, func.co_name, msg.encode('utf-8')))
|
title, func.co_name, msg.encode('utf-8')),
|
||||||
|
level=kodiLevel[level])
|
||||||
except:
|
except:
|
||||||
xbmc.log("%s -> %s : %s" % (title, func.co_name, 'COULDNT LOG'))
|
xbmc.log("%s -> %s : %s" % (
|
||||||
|
title, func.co_name, 'COULDNT LOG'),
|
||||||
|
level=kodiLevel[level])
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
xbmc.log("%s -> %s" % (title, msg))
|
xbmc.log("%s -> %s" % (title, msg), level=kodiLevel[level])
|
||||||
except UnicodeEncodeError:
|
except UnicodeEncodeError:
|
||||||
try:
|
try:
|
||||||
xbmc.log("%s -> %s" % (title, msg.encode('utf-8')))
|
xbmc.log("%s -> %s" % (title, msg.encode('utf-8')),
|
||||||
|
level=kodiLevel[level])
|
||||||
except:
|
except:
|
||||||
xbmc.log("%s -> %s " % (title, 'COULDNT LOG'))
|
xbmc.log("%s -> %s " % (title, 'COULDNT LOG'),
|
||||||
|
level=kodiLevel[level])
|
||||||
|
|
||||||
|
|
||||||
def window(property, value=None, clear=False, windowid=10000):
|
def window(property, value=None, clear=False, windowid=10000):
|
||||||
# Get or set window property
|
"""
|
||||||
|
Get or set window property - thread safe!
|
||||||
|
|
||||||
|
Returns unicode.
|
||||||
|
|
||||||
|
Property needs to be string; value may be string or unicode
|
||||||
|
"""
|
||||||
WINDOW = xbmcgui.Window(windowid)
|
WINDOW = xbmcgui.Window(windowid)
|
||||||
|
|
||||||
#setproperty accepts both string and unicode but utf-8 strings are adviced by kodi devs because some unicode can give issues
|
#setproperty accepts both string and unicode but utf-8 strings are adviced by kodi devs because some unicode can give issues
|
||||||
|
@ -228,14 +243,13 @@ def window(property, value=None, clear=False, windowid=10000):
|
||||||
if clear:
|
if clear:
|
||||||
WINDOW.clearProperty(property)
|
WINDOW.clearProperty(property)
|
||||||
elif value is not None:
|
elif value is not None:
|
||||||
# Takes unicode or string by default!
|
WINDOW.setProperty(property, value.encode('utf-8'))
|
||||||
WINDOW.setProperty(property, value)
|
else:
|
||||||
else: #getproperty returns string so convert to unicode
|
return WINDOW.getProperty(property).decode('utf-8')
|
||||||
return WINDOW.getProperty(property)
|
|
||||||
|
|
||||||
def settings(setting, value=None):
|
def settings(setting, value=None):
|
||||||
"""
|
"""
|
||||||
Get or add addon setting.
|
Get or add addon setting. Returns unicode
|
||||||
|
|
||||||
Settings needs to be string
|
Settings needs to be string
|
||||||
Value can either be unicode or string
|
Value can either be unicode or string
|
||||||
|
@ -244,10 +258,10 @@ def settings(setting, value=None):
|
||||||
|
|
||||||
if value is not None:
|
if value is not None:
|
||||||
# Takes string or unicode by default!
|
# Takes string or unicode by default!
|
||||||
addon.setSetting(setting, value)
|
addon.setSetting(setting, value.encode('utf-8'))
|
||||||
else:
|
else:
|
||||||
# Returns unicode by default!
|
# Should return unicode by default, but just in case
|
||||||
return addon.getSetting(setting)
|
return addon.getSetting(setting).decode('utf-8')
|
||||||
|
|
||||||
def language(stringid):
|
def language(stringid):
|
||||||
# Central string retrieval
|
# Central string retrieval
|
||||||
|
@ -443,7 +457,7 @@ def reset():
|
||||||
logMsg("PLEX", "Deleting: settings.xml", 1)
|
logMsg("PLEX", "Deleting: settings.xml", 1)
|
||||||
|
|
||||||
dialog.ok(
|
dialog.ok(
|
||||||
heading="Emby for Kodi",
|
heading=addonName,
|
||||||
line1="Database reset has completed, Kodi will now restart to apply the changes.")
|
line1="Database reset has completed, Kodi will now restart to apply the changes.")
|
||||||
xbmc.executebuiltin('RestartApp')
|
xbmc.executebuiltin('RestartApp')
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
import shutil
|
import shutil
|
||||||
import xml.etree.ElementTree as etree
|
import xml.etree.ElementTree as etree
|
||||||
from os import path as ospath
|
|
||||||
|
|
||||||
import xbmc
|
import xbmc
|
||||||
import xbmcvfs
|
import xbmcvfs
|
||||||
|
|
|
@ -21,12 +21,13 @@
|
||||||
<setting label="30517" type="action" action="RunPlugin(plugin://plugin.video.plexkodiconnect?mode=passwords)" option="close" /><!-- Network credentials -->
|
<setting label="30517" type="action" action="RunPlugin(plugin://plugin.video.plexkodiconnect?mode=passwords)" option="close" /><!-- Network credentials -->
|
||||||
<setting id="accessToken" type="text" visible="false" default="" />
|
<setting id="accessToken" type="text" visible="false" default="" />
|
||||||
<setting id="pathsub" type="bool" visible="false" default="false" />
|
<setting id="pathsub" type="bool" visible="false" default="false" />
|
||||||
|
<setting label="39024" type="action" action="RunPlugin(plugin://plugin.video.plexkodiconnect?mode=reConnect)" option="close" />
|
||||||
</category>
|
</category>
|
||||||
|
|
||||||
<category label="plex.tv"><!-- plex.tv -->
|
<category label="plex.tv"><!-- plex.tv -->
|
||||||
<!-- Primary address -->
|
<!-- Primary address -->
|
||||||
<setting id="myplexlogin" label="39025" type="bool" default="true" /> <!-- Log into plex.tv on startup -->
|
<setting id="myplexlogin" label="39025" type="bool" default="true" /> <!-- Log into plex.tv on startup -->
|
||||||
<setting id="doPlexTvLogin" label="39024" type="action" action="RunPlugin(plugin://plugin.video.plexkodiconnect?mode=doPlexTvLogin)" option="close" />
|
<setting label="39209" type="action" action="RunPlugin(plugin://plugin.video.plexkodiconnect?mode=reConnect)" option="close" />
|
||||||
|
|
||||||
<setting id="plexLogin" label="plex.tv username" type="text" default="" visible="false" />
|
<setting id="plexLogin" label="plex.tv username" type="text" default="" visible="false" />
|
||||||
<setting id="plexhome" label="Plex home in use" type="bool" default="" visible="false" />
|
<setting id="plexhome" label="Plex home in use" type="bool" default="" visible="false" />
|
||||||
|
|
10
service.py
10
service.py
|
@ -171,8 +171,7 @@ class Service():
|
||||||
self.welcome_msg = False
|
self.welcome_msg = False
|
||||||
xbmcgui.Dialog().notification(
|
xbmcgui.Dialog().notification(
|
||||||
heading=self.addonName,
|
heading=self.addonName,
|
||||||
message=("%s %s" % (lang(33000), user.currUser)
|
message="%s %s" % (lang(33000), user.currUser),
|
||||||
).encode('utf-8'),
|
|
||||||
icon="special://home/addons/plugin.video.plexkodiconnect/icon.png",
|
icon="special://home/addons/plugin.video.plexkodiconnect/icon.png",
|
||||||
time=2000,
|
time=2000,
|
||||||
sound=False)
|
sound=False)
|
||||||
|
@ -225,8 +224,9 @@ class Service():
|
||||||
window('emby_online', value="false")
|
window('emby_online', value="false")
|
||||||
|
|
||||||
xbmcgui.Dialog().notification(
|
xbmcgui.Dialog().notification(
|
||||||
heading=lang(33001).encode('utf-8'),
|
heading=lang(33001),
|
||||||
message=("%s %s" % (self.addonName, lang(33002))).encode('utf-8'),
|
message="%s %s"
|
||||||
|
% (self.addonName, lang(33002)),
|
||||||
icon="special://home/addons/plugin.video."
|
icon="special://home/addons/plugin.video."
|
||||||
"plexkodiconnect/icon.png",
|
"plexkodiconnect/icon.png",
|
||||||
sound=False)
|
sound=False)
|
||||||
|
@ -244,7 +244,7 @@ class Service():
|
||||||
# Alert the user that server is online.
|
# Alert the user that server is online.
|
||||||
xbmcgui.Dialog().notification(
|
xbmcgui.Dialog().notification(
|
||||||
heading=self.addonName,
|
heading=self.addonName,
|
||||||
message=lang(33003).encode('utf-8'),
|
message=lang(33003),
|
||||||
icon="special://home/addons/plugin.video."
|
icon="special://home/addons/plugin.video."
|
||||||
"plexkodiconnect/icon.png",
|
"plexkodiconnect/icon.png",
|
||||||
time=2000,
|
time=2000,
|
||||||
|
|
Loading…
Reference in a new issue