Merge branch 'develop'
This commit is contained in:
commit
f15ac366d8
20 changed files with 290 additions and 207 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="2.2.7"
|
version="2.2.8"
|
||||||
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,7 @@
|
||||||
|
version 2.2.8
|
||||||
|
- Fix to photos not displaying directories without picutres.
|
||||||
|
- Fix to grouped views causing crash
|
||||||
|
|
||||||
version 2.2.7
|
version 2.2.7
|
||||||
- Prevent Kodi screensaver during the initial sync
|
- Prevent Kodi screensaver during the initial sync
|
||||||
|
|
||||||
|
|
12
default.py
12
default.py
|
@ -51,7 +51,6 @@ class Main:
|
||||||
|
|
||||||
'reset': utils.reset,
|
'reset': utils.reset,
|
||||||
'resetauth': entrypoint.resetAuth,
|
'resetauth': entrypoint.resetAuth,
|
||||||
'extrafanart': entrypoint.getExtraFanArt,
|
|
||||||
'play': entrypoint.doPlayback,
|
'play': entrypoint.doPlayback,
|
||||||
'passwords': utils.passwordsXML,
|
'passwords': utils.passwordsXML,
|
||||||
'adduser': entrypoint.addUser,
|
'adduser': entrypoint.addUser,
|
||||||
|
@ -70,8 +69,15 @@ class Main:
|
||||||
'doPlexTvLogin': entrypoint.doPlexTvLogin
|
'doPlexTvLogin': entrypoint.doPlexTvLogin
|
||||||
}
|
}
|
||||||
|
|
||||||
if "extrafanart" in sys.argv[0]:
|
if "/extrafanart" in sys.argv[0]:
|
||||||
entrypoint.getExtraFanArt()
|
embypath = sys.argv[2][1:]
|
||||||
|
embyid = params.get('id',[""])[0]
|
||||||
|
entrypoint.getExtraFanArt(embyid,embypath)
|
||||||
|
|
||||||
|
if "/Extras" in sys.argv[0] or "/VideoFiles" in sys.argv[0]:
|
||||||
|
embypath = sys.argv[2][1:]
|
||||||
|
embyid = params.get('id',[""])[0]
|
||||||
|
entrypoint.getVideoFiles(embyid,embypath)
|
||||||
|
|
||||||
if modes.get(mode):
|
if modes.get(mode):
|
||||||
# Simple functions
|
# Simple functions
|
||||||
|
|
|
@ -364,6 +364,7 @@
|
||||||
<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]Log into plex.tv[/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>
|
||||||
|
|
||||||
|
|
||||||
<!-- Plex Entrypoint.py -->
|
<!-- Plex Entrypoint.py -->
|
||||||
|
|
|
@ -295,6 +295,7 @@
|
||||||
<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]Bei plex.tv einloggen[/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>
|
||||||
|
|
||||||
<!-- Plex Entrypoint.py -->
|
<!-- Plex Entrypoint.py -->
|
||||||
<string id="39200">Plex Home Benutzer wechseln</string>
|
<string id="39200">Plex Home Benutzer wechseln</string>
|
||||||
|
|
|
@ -79,7 +79,6 @@ class PlexAPI():
|
||||||
self.deviceName = client.getDeviceName()
|
self.deviceName = client.getDeviceName()
|
||||||
self.plexversion = client.getVersion()
|
self.plexversion = client.getVersion()
|
||||||
self.platform = client.getPlatform()
|
self.platform = client.getPlatform()
|
||||||
self.user = utils.window('plex_username')
|
|
||||||
self.userId = utils.window('emby_currUser')
|
self.userId = utils.window('emby_currUser')
|
||||||
self.token = utils.window('emby_accessToken%s' % self.userId)
|
self.token = utils.window('emby_accessToken%s' % self.userId)
|
||||||
self.server = utils.window('emby_server%s' % self.userId)
|
self.server = utils.window('emby_server%s' % self.userId)
|
||||||
|
@ -95,13 +94,15 @@ class PlexAPI():
|
||||||
'plexid': utils.settings('plexid'),
|
'plexid': utils.settings('plexid'),
|
||||||
'myplexlogin': utils.settings('myplexlogin')
|
'myplexlogin': utils.settings('myplexlogin')
|
||||||
|
|
||||||
|
plexLogin is unicode or empty unicode string u''
|
||||||
|
|
||||||
Returns empty strings '' for a setting if not found.
|
Returns empty strings '' for a setting if not found.
|
||||||
|
|
||||||
myplexlogin is 'true' if user opted to log into plex.tv (the default)
|
myplexlogin is 'true' if user opted to log into plex.tv (the default)
|
||||||
plexhome is 'true' if plex home is used (the default)
|
plexhome is 'true' if plex home is used (the default)
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
'plexLogin': utils.settings('plexLogin'),
|
'plexLogin': utils.settings('plexLogin').decode('utf-8'),
|
||||||
'plexToken': utils.settings('plexToken'),
|
'plexToken': utils.settings('plexToken'),
|
||||||
'plexhome': utils.settings('plexhome'),
|
'plexhome': utils.settings('plexhome'),
|
||||||
'plexid': utils.settings('plexid'),
|
'plexid': utils.settings('plexid'),
|
||||||
|
@ -127,32 +128,31 @@ class PlexAPI():
|
||||||
retrievedPlexLogin = ''
|
retrievedPlexLogin = ''
|
||||||
plexLogin = 'dummy'
|
plexLogin = 'dummy'
|
||||||
authtoken = ''
|
authtoken = ''
|
||||||
|
dialog = xbmcgui.Dialog()
|
||||||
while retrievedPlexLogin == '' and plexLogin != '':
|
while retrievedPlexLogin == '' and plexLogin != '':
|
||||||
dialog = xbmcgui.Dialog()
|
|
||||||
# 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 != "":
|
||||||
dialog = xbmcgui.Dialog()
|
|
||||||
# Enter password for plex.tv user
|
# Enter password for plex.tv user
|
||||||
plexPassword = dialog.input(
|
plexPassword = dialog.input(
|
||||||
string(39301) + plexLogin,
|
string(39301).encode('utf-8') + plexLogin.encode('utf-8'),
|
||||||
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,
|
||||||
{'X-Plex-Client-Identifier': self.clientId}
|
{'X-Plex-Client-Identifier': self.clientId})
|
||||||
)
|
|
||||||
self.logMsg("plex.tv username and token: %s, %s"
|
self.logMsg("plex.tv username and token: %s, %s"
|
||||||
% (plexLogin, authtoken), 1)
|
% (plexLogin, authtoken), 1)
|
||||||
if plexLogin == '':
|
if plexLogin == '':
|
||||||
dialog = xbmcgui.Dialog()
|
|
||||||
# Could not sign in user
|
# Could not sign in user
|
||||||
dialog.ok(self.addonName, string(39302) + plexLogin)
|
dialog.ok(self.addonName,
|
||||||
|
string(39302).encode('utf-8')
|
||||||
|
+ 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 +177,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))
|
dialog.ok(self.addonName, string(39303).encode('utf-8'))
|
||||||
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",
|
(string(39304) + "\n\n").encode('utf-8'),
|
||||||
code)
|
code.encode('utf-8'))
|
||||||
if not answer:
|
if not answer:
|
||||||
return False
|
return False
|
||||||
count = 0
|
count = 0
|
||||||
|
@ -196,7 +196,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))
|
dialog.ok(self.addonName, string(39305).encode('utf-8'))
|
||||||
return False
|
return False
|
||||||
# Parse xml
|
# Parse xml
|
||||||
userid = xml.attrib.get('id')
|
userid = xml.attrib.get('id')
|
||||||
|
@ -259,11 +259,11 @@ class PlexAPI():
|
||||||
try:
|
try:
|
||||||
code = xml.find('code').text
|
code = xml.find('code').text
|
||||||
identifier = xml.find('id').text
|
identifier = xml.find('id').text
|
||||||
|
self.logMsg('Successfully retrieved code and id from plex.tv', 1)
|
||||||
|
return code, identifier
|
||||||
except:
|
except:
|
||||||
self.logMsg("Error, no PIN from plex.tv provided", -1)
|
self.logMsg("Error, no PIN from plex.tv provided", -1)
|
||||||
self.logMsg("plex.tv/pin: Code is: %s" % code, 2)
|
return None, None
|
||||||
self.logMsg("plex.tv/pin: Identifier is: %s" % identifier, 2)
|
|
||||||
return code, identifier
|
|
||||||
|
|
||||||
def TalkToPlexServer(self, url, talkType="GET", verify=True, token=None):
|
def TalkToPlexServer(self, url, talkType="GET", verify=True, token=None):
|
||||||
"""
|
"""
|
||||||
|
@ -345,8 +345,8 @@ class PlexAPI():
|
||||||
sslverify = True
|
sslverify = True
|
||||||
else:
|
else:
|
||||||
sslverify = False
|
sslverify = False
|
||||||
self.logMsg("Checking connection to server %s with header %s and "
|
self.logMsg("Checking connection to server %s with sslverify=%s"
|
||||||
"sslverify=%s" % (url, header, sslverify), 1)
|
% (url, sslverify), 1)
|
||||||
timeout = (3, 10)
|
timeout = (3, 10)
|
||||||
if 'plex.tv' in url:
|
if 'plex.tv' in url:
|
||||||
url = 'https://plex.tv/api/home/users'
|
url = 'https://plex.tv/api/home/users'
|
||||||
|
@ -814,7 +814,6 @@ class PlexAPI():
|
||||||
'X-Plex-Version': self.plexversion,
|
'X-Plex-Version': self.plexversion,
|
||||||
'X-Plex-Client-Identifier': self.clientId,
|
'X-Plex-Client-Identifier': self.clientId,
|
||||||
'X-Plex-Provides': 'player',
|
'X-Plex-Provides': 'player',
|
||||||
'X-Plex-Username': self.user,
|
|
||||||
'X-Plex-Client-Capabilities': 'protocols=shoutcast,http-video;videoDecoders=h264{profile:high&resolution:1080&level:51};audioDecoders=mp3,aac,dts{bitrate:800000&channels:8},ac3{bitrate:800000&channels:8}',
|
'X-Plex-Client-Capabilities': 'protocols=shoutcast,http-video;videoDecoders=h264{profile:high&resolution:1080&level:51};audioDecoders=mp3,aac,dts{bitrate:800000&channels:8},ac3{bitrate:800000&channels:8}',
|
||||||
'X-Plex-Client-Profile-Extra': 'add-transcode-target-audio-codec(type=videoProfile&context=streaming&protocol=*&audioCodec=dca,ac3)',
|
'X-Plex-Client-Profile-Extra': 'add-transcode-target-audio-codec(type=videoProfile&context=streaming&protocol=*&audioCodec=dca,ac3)',
|
||||||
}
|
}
|
||||||
|
@ -1042,6 +1041,8 @@ class PlexAPI():
|
||||||
self.logMsg("No URL for user avatar.", 1)
|
self.logMsg("No URL for user avatar.", 1)
|
||||||
return False
|
return False
|
||||||
for user in users:
|
for user in users:
|
||||||
|
self.logMsg('type user: %s, type username: %s'
|
||||||
|
% (type(user['title']), type(username)))
|
||||||
if username in user['title']:
|
if username in user['title']:
|
||||||
url = user['thumb']
|
url = user['thumb']
|
||||||
self.logMsg("Avatar url for user %s is: %s" % (username, url), 1)
|
self.logMsg("Avatar url for user %s is: %s" % (username, url), 1)
|
||||||
|
@ -1060,6 +1061,7 @@ class PlexAPI():
|
||||||
Will return empty strings if failed.
|
Will return empty strings if failed.
|
||||||
"""
|
"""
|
||||||
string = self.__language__
|
string = self.__language__
|
||||||
|
dialog = xbmcgui.Dialog()
|
||||||
|
|
||||||
plexLogin = utils.settings('plexLogin')
|
plexLogin = utils.settings('plexLogin')
|
||||||
plexToken = utils.settings('plexToken')
|
plexToken = utils.settings('plexToken')
|
||||||
|
@ -1074,19 +1076,21 @@ class PlexAPI():
|
||||||
return ('', '', '')
|
return ('', '', '')
|
||||||
|
|
||||||
userlist = []
|
userlist = []
|
||||||
|
userlistCoded = []
|
||||||
for user in users:
|
for user in users:
|
||||||
username = user['title']
|
username = user['title']
|
||||||
userlist.append(username)
|
userlist.append(username)
|
||||||
|
userlistCoded.append(username.encode('utf-8'))
|
||||||
usernumber = len(userlist)
|
usernumber = len(userlist)
|
||||||
usertoken = ''
|
usertoken = ''
|
||||||
# Plex home not in use: only 1 user returned
|
# Plex home not in use: only 1 user returned
|
||||||
trials = 0
|
trials = 0
|
||||||
while trials < 3:
|
while trials < 3:
|
||||||
if usernumber > 1:
|
if usernumber > 1:
|
||||||
dialog = xbmcgui.Dialog()
|
|
||||||
# Select user
|
# Select user
|
||||||
user_select = dialog.select(self.addonName + string(39306),
|
user_select = dialog.select(
|
||||||
userlist)
|
(self.addonName + string(39306)).encode('utf-8'),
|
||||||
|
userlistCoded)
|
||||||
if user_select == -1:
|
if user_select == -1:
|
||||||
self.logMsg("No user selected.", 1)
|
self.logMsg("No user selected.", 1)
|
||||||
xbmc.executebuiltin('Addon.OpenSettings(%s)'
|
xbmc.executebuiltin('Addon.OpenSettings(%s)'
|
||||||
|
@ -1101,11 +1105,10 @@ class PlexAPI():
|
||||||
user = users[user_select]
|
user = users[user_select]
|
||||||
# Ask for PIN, if protected:
|
# Ask for PIN, if protected:
|
||||||
if user['protected'] == '1':
|
if user['protected'] == '1':
|
||||||
dialog = xbmcgui.Dialog()
|
|
||||||
# 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,
|
(string(39307) + selected_user).encode('utf-8'),
|
||||||
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
|
||||||
|
@ -1114,6 +1117,9 @@ class PlexAPI():
|
||||||
else:
|
else:
|
||||||
pin = None
|
pin = None
|
||||||
# Switch to this Plex Home user, if applicable
|
# Switch to this Plex Home user, if applicable
|
||||||
|
# Plex bug: don't call url for protected user with empty PIN
|
||||||
|
if user['protected'] == '1' and not pin:
|
||||||
|
break
|
||||||
username, usertoken = self.PlexSwitchHomeUser(
|
username, usertoken = self.PlexSwitchHomeUser(
|
||||||
user['id'],
|
user['id'],
|
||||||
pin,
|
pin,
|
||||||
|
@ -1122,12 +1128,11 @@ class PlexAPI():
|
||||||
)
|
)
|
||||||
# Couldn't get user auth
|
# Couldn't get user auth
|
||||||
if not username:
|
if not username:
|
||||||
dialog = xbmcgui.Dialog()
|
|
||||||
# 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
|
||||||
|
@ -1158,8 +1163,7 @@ class PlexAPI():
|
||||||
url = 'https://plex.tv/api/home/users/' + userId + '/switch'
|
url = 'https://plex.tv/api/home/users/' + userId + '/switch'
|
||||||
if pin:
|
if pin:
|
||||||
url += '?pin=' + pin
|
url += '?pin=' + pin
|
||||||
self.logMsg('Switching to user %s with url %s and machineId %s'
|
self.logMsg('Switching to user %s' % userId, 0)
|
||||||
% (userId, url, machineId), 0)
|
|
||||||
answer = self.TalkToPlexServer(url, talkType="POST", token=token)
|
answer = self.TalkToPlexServer(url, talkType="POST", token=token)
|
||||||
if not answer:
|
if not answer:
|
||||||
self.logMsg('Error: plex.tv switch HomeUser change failed', -1)
|
self.logMsg('Error: plex.tv switch HomeUser change failed', -1)
|
||||||
|
@ -1188,7 +1192,7 @@ class PlexAPI():
|
||||||
self.logMsg("username: %s, token: xxxx. "
|
self.logMsg("username: %s, token: xxxx. "
|
||||||
"Saving to window and file settings" % username, 0)
|
"Saving to window and file settings" % username, 0)
|
||||||
utils.window('emby_currUser', value=userId)
|
utils.window('emby_currUser', value=userId)
|
||||||
utils.settings('userId%s' % username, value=userId)
|
utils.settings('userId', value=userId)
|
||||||
utils.settings('username', value=username)
|
utils.settings('username', value=username)
|
||||||
utils.window('emby_accessToken%s' % userId, value=token)
|
utils.window('emby_accessToken%s' % userId, value=token)
|
||||||
return (username, token)
|
return (username, token)
|
||||||
|
@ -1411,7 +1415,6 @@ class API():
|
||||||
self.part = 0
|
self.part = 0
|
||||||
self.clientinfo = clientinfo.ClientInfo()
|
self.clientinfo = clientinfo.ClientInfo()
|
||||||
self.clientId = self.clientinfo.getDeviceId()
|
self.clientId = self.clientinfo.getDeviceId()
|
||||||
self.user = utils.window('plex_username')
|
|
||||||
self.userId = utils.window('emby_currUser')
|
self.userId = utils.window('emby_currUser')
|
||||||
self.server = utils.window('emby_server%s' % self.userId)
|
self.server = utils.window('emby_server%s' % self.userId)
|
||||||
self.token = utils.window('emby_accessToken%s' % self.userId)
|
self.token = utils.window('emby_accessToken%s' % self.userId)
|
||||||
|
|
|
@ -162,7 +162,8 @@ class Artwork():
|
||||||
import xbmcaddon
|
import xbmcaddon
|
||||||
string = xbmcaddon.Addon().getLocalizedString
|
string = xbmcaddon.Addon().getLocalizedString
|
||||||
|
|
||||||
if not xbmcgui.Dialog().yesno("Image Texture Cache", string(39250)):
|
if not xbmcgui.Dialog().yesno(
|
||||||
|
"Image Texture Cache", string(39250).encode('utf-8')):
|
||||||
return
|
return
|
||||||
|
|
||||||
self.logMsg("Doing Image Cache Sync", 1)
|
self.logMsg("Doing Image Cache Sync", 1)
|
||||||
|
@ -171,11 +172,12 @@ class Artwork():
|
||||||
dialog.create("Emby for Kodi", "Image Cache Sync")
|
dialog.create("Emby for Kodi", "Image Cache Sync")
|
||||||
|
|
||||||
# ask to rest all existing or not
|
# ask to rest all existing or not
|
||||||
if xbmcgui.Dialog().yesno("Image Texture Cache", string(39251), ""):
|
if xbmcgui.Dialog().yesno(
|
||||||
|
"Image Texture Cache", string(39251).encode('utf-8'), ""):
|
||||||
self.logMsg("Resetting all cache data first", 1)
|
self.logMsg("Resetting all cache data first", 1)
|
||||||
# Remove all existing textures first
|
# Remove all existing textures first
|
||||||
path = xbmc.translatePath("special://thumbnails/").decode('utf-8')
|
path = xbmc.translatePath("special://thumbnails/").decode('utf-8')
|
||||||
if xbmcvfs.exists(path):
|
if utils.IfExists(path):
|
||||||
allDirs, allFiles = xbmcvfs.listdir(path)
|
allDirs, allFiles = xbmcvfs.listdir(path)
|
||||||
for dir in allDirs:
|
for dir in allDirs:
|
||||||
allDirs, allFiles = xbmcvfs.listdir(path+dir)
|
allDirs, allFiles = xbmcvfs.listdir(path+dir)
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import urlparse
|
|
||||||
|
|
||||||
import xbmc
|
import xbmc
|
||||||
import xbmcaddon
|
import xbmcaddon
|
||||||
|
@ -156,7 +155,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))
|
line1=string(39206).encode('utf-8'))
|
||||||
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")
|
||||||
|
@ -226,14 +225,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))
|
line1=language(33032).encode('utf-8'))
|
||||||
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))
|
line1=language(33033).encode('utf-8'))
|
||||||
xbmc.executebuiltin('RestartApp')
|
xbmc.executebuiltin('RestartApp')
|
||||||
|
|
||||||
##### ADD ADDITIONAL USERS #####
|
##### ADD ADDITIONAL USERS #####
|
||||||
|
@ -399,7 +398,7 @@ def getThemeMedia():
|
||||||
library = xbmc.translatePath(
|
library = xbmc.translatePath(
|
||||||
"special://profile/addon_data/plugin.video.plexkodiconnect/library/").decode('utf-8')
|
"special://profile/addon_data/plugin.video.plexkodiconnect/library/").decode('utf-8')
|
||||||
# Create library directory
|
# Create library directory
|
||||||
if not xbmcvfs.exists(library):
|
if not utils.IfExists(library):
|
||||||
xbmcvfs.mkdir(library)
|
xbmcvfs.mkdir(library)
|
||||||
|
|
||||||
# Set custom path for user
|
# Set custom path for user
|
||||||
|
@ -572,10 +571,10 @@ def BrowseContent(viewname, type="", folderid=""):
|
||||||
if not folderid:
|
if not folderid:
|
||||||
views = emby.getViews(type)
|
views = emby.getViews(type)
|
||||||
for view in views:
|
for view in views:
|
||||||
if view.get("name") == viewname:
|
if view.get("name") == viewname.decode('utf-8'):
|
||||||
folderid = view.get("id")
|
folderid = view.get("id")
|
||||||
|
|
||||||
utils.logMsg("BrowseContent","viewname: %s - type: %s - folderid: %s - filter: %s" %(viewname, type, folderid, filter))
|
utils.logMsg("BrowseContent","viewname: %s - type: %s - folderid: %s - filter: %s" %(viewname.decode('utf-8'), type.decode('utf-8'), folderid.decode('utf-8'), filter.decode('utf-8')))
|
||||||
#set the correct params for the content type
|
#set the correct params for the content type
|
||||||
#only proceed if we have a folderid
|
#only proceed if we have a folderid
|
||||||
if folderid:
|
if folderid:
|
||||||
|
@ -584,7 +583,7 @@ def BrowseContent(viewname, type="", folderid=""):
|
||||||
itemtype = "Video,Folder,PhotoAlbum"
|
itemtype = "Video,Folder,PhotoAlbum"
|
||||||
elif type.lower() == "photos":
|
elif type.lower() == "photos":
|
||||||
xbmcplugin.setContent(int(sys.argv[1]), 'files')
|
xbmcplugin.setContent(int(sys.argv[1]), 'files')
|
||||||
itemtype = "Photo,PhotoAlbum"
|
itemtype = "Photo,PhotoAlbum,Folder"
|
||||||
else:
|
else:
|
||||||
itemtype = ""
|
itemtype = ""
|
||||||
|
|
||||||
|
@ -610,14 +609,13 @@ def BrowseContent(viewname, type="", folderid=""):
|
||||||
li = createListItemFromEmbyItem(item,art,doUtils)
|
li = createListItemFromEmbyItem(item,art,doUtils)
|
||||||
if item.get("IsFolder") == True:
|
if item.get("IsFolder") == True:
|
||||||
#for folders we add an additional browse request, passing the folderId
|
#for folders we add an additional browse request, passing the folderId
|
||||||
path = "%s?id=%s&mode=browsecontent&type=%s&folderid=%s" % (sys.argv[0], viewname, type, item.get("Id"))
|
path = "%s?id=%s&mode=browsecontent&type=%s&folderid=%s" % (sys.argv[0].decode('utf-8'), viewname.decode('utf-8'), type.decode('utf-8'), item.get("Id").decode('utf-8'))
|
||||||
xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=path, listitem=li, isFolder=True)
|
xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=path, listitem=li, isFolder=True)
|
||||||
else:
|
else:
|
||||||
#playable item, set plugin path and mediastreams
|
#playable item, set plugin path and mediastreams
|
||||||
xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=li.getProperty("path"), listitem=li)
|
xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=li.getProperty("path"), listitem=li)
|
||||||
|
|
||||||
|
|
||||||
xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))
|
|
||||||
if filter == "recent":
|
if filter == "recent":
|
||||||
xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_DATE)
|
xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_DATE)
|
||||||
else:
|
else:
|
||||||
|
@ -626,6 +624,8 @@ def BrowseContent(viewname, type="", folderid=""):
|
||||||
xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_VIDEO_RATING)
|
xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_VIDEO_RATING)
|
||||||
xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_VIDEO_RUNTIME)
|
xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_VIDEO_RUNTIME)
|
||||||
|
|
||||||
|
xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))
|
||||||
|
|
||||||
##### CREATE LISTITEM FROM EMBY METADATA #####
|
##### CREATE LISTITEM FROM EMBY METADATA #####
|
||||||
def createListItemFromEmbyItem(item,art=artwork.Artwork(),doUtils=downloadutils.DownloadUtils()):
|
def createListItemFromEmbyItem(item,art=artwork.Artwork(),doUtils=downloadutils.DownloadUtils()):
|
||||||
API = api.API(item)
|
API = api.API(item)
|
||||||
|
@ -1066,28 +1066,45 @@ def getRecentEpisodes(tagname, limit):
|
||||||
|
|
||||||
xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))
|
xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))
|
||||||
|
|
||||||
|
##### GET VIDEO EXTRAS FOR LISTITEM #####
|
||||||
|
def getVideoFiles(embyId,embyPath):
|
||||||
|
#returns the video files for the item as plugin listing, can be used for browsing the actual files or videoextras etc.
|
||||||
|
emby = embyserver.Read_EmbyServer()
|
||||||
|
if not embyId:
|
||||||
|
if "plugin.video.emby" in embyPath:
|
||||||
|
embyId = embyPath.split("/")[-2]
|
||||||
|
if embyId:
|
||||||
|
item = emby.getItem(embyId)
|
||||||
|
putils = playutils.PlayUtils(item)
|
||||||
|
if putils.isDirectPlay():
|
||||||
|
#only proceed if we can access the files directly. TODO: copy local on the fly if accessed outside
|
||||||
|
filelocation = putils.directPlay()
|
||||||
|
if not filelocation.endswith("/"):
|
||||||
|
filelocation = filelocation.rpartition("/")[0]
|
||||||
|
dirs, files = xbmcvfs.listdir(filelocation)
|
||||||
|
for file in files:
|
||||||
|
file = filelocation + file
|
||||||
|
li = xbmcgui.ListItem(file, path=file)
|
||||||
|
xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=file, listitem=li)
|
||||||
|
for dir in dirs:
|
||||||
|
dir = filelocation + dir
|
||||||
|
li = xbmcgui.ListItem(dir, path=dir)
|
||||||
|
xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=dir, listitem=li, isFolder=True)
|
||||||
|
xbmcplugin.endOfDirectory(int(sys.argv[1]))
|
||||||
|
|
||||||
##### GET EXTRAFANART FOR LISTITEM #####
|
##### GET EXTRAFANART FOR LISTITEM #####
|
||||||
def getExtraFanArt():
|
def getExtraFanArt(embyId,embyPath):
|
||||||
|
|
||||||
emby = embyserver.Read_EmbyServer()
|
emby = embyserver.Read_EmbyServer()
|
||||||
art = artwork.Artwork()
|
art = artwork.Artwork()
|
||||||
embyId = ""
|
|
||||||
|
|
||||||
# Get extrafanart for listitem
|
# Get extrafanart for listitem
|
||||||
# will be called by skinhelper script to get the extrafanart
|
# will be called by skinhelper script to get the extrafanart
|
||||||
try:
|
try:
|
||||||
# for tvshows we get the embyid just from the path
|
# for tvshows we get the embyid just from the path
|
||||||
if xbmc.getCondVisibility("Container.Content(tvshows) | Container.Content(seasons) | Container.Content(episodes)"):
|
if not embyId:
|
||||||
itemPath = xbmc.getInfoLabel("ListItem.Path").decode('utf-8')
|
if "plugin.video.emby" in embyPath:
|
||||||
if "plugin.video.plexkodiconnect" in itemPath:
|
embyId = embyPath.split("/")[-2]
|
||||||
embyId = itemPath.split("/")[-2]
|
|
||||||
else:
|
|
||||||
#for movies we grab the emby id from the params
|
|
||||||
itemPath = xbmc.getInfoLabel("ListItem.FileNameAndPath").decode('utf-8')
|
|
||||||
if "plugin.video.plexkodiconnect" in itemPath:
|
|
||||||
params = urlparse.parse_qs(itemPath)
|
|
||||||
embyId = params.get('id')
|
|
||||||
if embyId: embyId = embyId[0]
|
|
||||||
|
|
||||||
if embyId:
|
if embyId:
|
||||||
#only proceed if we actually have a emby id
|
#only proceed if we actually have a emby id
|
||||||
|
@ -1131,7 +1148,7 @@ def getExtraFanArt():
|
||||||
url=fanartFile,
|
url=fanartFile,
|
||||||
listitem=li)
|
listitem=li)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
utils.logMsg("EMBY", "Error getting extrafanart: %s" % e, 1)
|
utils.logMsg("EMBY", "Error getting extrafanart: %s" % e, 0)
|
||||||
|
|
||||||
# Always do endofdirectory to prevent errors in the logs
|
# Always do endofdirectory to prevent errors in the logs
|
||||||
xbmcplugin.endOfDirectory(int(sys.argv[1]))
|
xbmcplugin.endOfDirectory(int(sys.argv[1]))
|
||||||
|
@ -1142,6 +1159,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))
|
line1=string(39205).encode('utf-8'))
|
||||||
else:
|
else:
|
||||||
utils.window('plex_runLibScan', value='full')
|
utils.window('plex_runLibScan', value='full')
|
||||||
|
|
|
@ -20,10 +20,6 @@ import PlexAPI
|
||||||
class InitialSetup():
|
class InitialSetup():
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
self.addon = xbmcaddon.Addon()
|
|
||||||
self.__language__ = self.addon.getLocalizedString
|
|
||||||
|
|
||||||
self.clientInfo = clientinfo.ClientInfo()
|
self.clientInfo = clientinfo.ClientInfo()
|
||||||
self.addonId = self.clientInfo.getAddonId()
|
self.addonId = self.clientInfo.getAddonId()
|
||||||
self.doUtils = downloadutils.DownloadUtils()
|
self.doUtils = downloadutils.DownloadUtils()
|
||||||
|
@ -36,7 +32,7 @@ class InitialSetup():
|
||||||
Check server, user, direct paths, music, direct stream if not direct
|
Check server, user, direct paths, music, direct stream if not direct
|
||||||
path.
|
path.
|
||||||
"""
|
"""
|
||||||
string = self.__language__
|
string = xbmcaddon.Addon().getLocalizedString
|
||||||
# SERVER INFO #####
|
# SERVER INFO #####
|
||||||
self.logMsg("Initial setup called.", 0)
|
self.logMsg("Initial setup called.", 0)
|
||||||
server = self.userClient.getServer()
|
server = self.userClient.getServer()
|
||||||
|
@ -63,7 +59,7 @@ class InitialSetup():
|
||||||
# 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:
|
||||||
|
@ -74,7 +70,7 @@ class InitialSetup():
|
||||||
# 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:
|
||||||
|
@ -92,36 +88,40 @@ class InitialSetup():
|
||||||
plexToken = result['token']
|
plexToken = result['token']
|
||||||
plexid = result['plexid']
|
plexid = result['plexid']
|
||||||
# Get g_PMS list of servers (saved to plx.g_PMS)
|
# Get g_PMS list of servers (saved to plx.g_PMS)
|
||||||
|
httpsUpdated = False
|
||||||
while True:
|
while True:
|
||||||
tokenDict = {'MyPlexToken': plexToken} if plexToken else {}
|
if httpsUpdated is False:
|
||||||
# Populate g_PMS variable with the found Plex servers
|
tokenDict = {'MyPlexToken': plexToken} if plexToken else {}
|
||||||
self.plx.discoverPMS(clientId,
|
# Populate g_PMS variable with the found Plex servers
|
||||||
None,
|
self.plx.discoverPMS(clientId,
|
||||||
xbmc.getIPAddress(),
|
None,
|
||||||
tokenDict=tokenDict)
|
xbmc.getIPAddress(),
|
||||||
self.logMsg("Result of setting g_PMS variable: %s"
|
tokenDict=tokenDict)
|
||||||
% self.plx.g_PMS, 2)
|
self.logMsg("Result of setting g_PMS variable: %s"
|
||||||
isconnected = False
|
% self.plx.g_PMS, 1)
|
||||||
serverlist = self.plx.returnServerList(clientId, self.plx.g_PMS)
|
isconnected = False
|
||||||
# Let user pick server from a list
|
serverlist = self.plx.returnServerList(
|
||||||
# Get a nicer list
|
clientId, self.plx.g_PMS)
|
||||||
dialoglist = []
|
self.logMsg('PMS serverlist: %s' % serverlist)
|
||||||
# Exit if no servers found
|
# Let user pick server from a list
|
||||||
if len(serverlist) == 0:
|
# Get a nicer list
|
||||||
dialog.ok(
|
dialoglist = []
|
||||||
self.addonName,
|
# Exit if no servers found
|
||||||
string(39011)
|
if len(serverlist) == 0:
|
||||||
)
|
dialog.ok(
|
||||||
break
|
self.addonName,
|
||||||
for server in serverlist:
|
string(39011).encode('utf-8')
|
||||||
if server['local'] == '1':
|
)
|
||||||
# server is in the same network as client. Add "local"
|
break
|
||||||
dialoglist.append(str(server['name']) + string(39022))
|
for server in serverlist:
|
||||||
else:
|
if server['local'] == '1':
|
||||||
dialoglist.append(str(server['name']))
|
# server is in the same network as client. Add "local"
|
||||||
resp = dialog.select(
|
dialoglist.append(
|
||||||
string(39012),
|
server['name'].encode('utf-8')
|
||||||
dialoglist)
|
+ string(39022).encode('utf-8'))
|
||||||
|
else:
|
||||||
|
dialoglist.append(server['name'].encode('utf-8'))
|
||||||
|
resp = dialog.select(string(39012).encode('utf-8'), dialoglist)
|
||||||
server = serverlist[resp]
|
server = serverlist[resp]
|
||||||
activeServer = server['machineIdentifier']
|
activeServer = server['machineIdentifier']
|
||||||
url = server['scheme'] + '://' + server['ip'] + ':' + \
|
url = server['scheme'] + '://' + server['ip'] + ':' + \
|
||||||
|
@ -136,13 +136,19 @@ class InitialSetup():
|
||||||
self.logMsg("Setting SSL verify to true, because server is "
|
self.logMsg("Setting SSL verify to true, because server is "
|
||||||
"not local", 1)
|
"not local", 1)
|
||||||
chk = self.plx.CheckConnection(url, server['accesstoken'])
|
chk = self.plx.CheckConnection(url, server['accesstoken'])
|
||||||
# Unauthorized
|
if chk == 504 and httpsUpdated is False:
|
||||||
|
# Not able to use HTTP, try HTTPs for now
|
||||||
|
serverlist[resp]['scheme'] = 'https'
|
||||||
|
httpsUpdated = True
|
||||||
|
continue
|
||||||
|
httpsUpdated = False
|
||||||
if chk == 401:
|
if chk == 401:
|
||||||
# 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) + str(server['name']),
|
string(39013).encode('utf-8')
|
||||||
string(39014))
|
+ server['name'].encode('utf-8'),
|
||||||
|
string(39014).encode('utf-8'))
|
||||||
result = self.plx.PlexTvSignInWithPin()
|
result = self.plx.PlexTvSignInWithPin()
|
||||||
if result:
|
if result:
|
||||||
plexLogin = result['username']
|
plexLogin = result['username']
|
||||||
|
@ -154,7 +160,8 @@ class InitialSetup():
|
||||||
# Problems connecting
|
# Problems connecting
|
||||||
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, string(39015))
|
resp = dialog.yesno(self.addonName,
|
||||||
|
string(39015).encode('utf-8'))
|
||||||
# Exit while loop if user chooses No
|
# Exit while loop if user chooses No
|
||||||
if not resp:
|
if not resp:
|
||||||
break
|
break
|
||||||
|
@ -166,7 +173,7 @@ class InitialSetup():
|
||||||
# Enter Kodi settings instead
|
# Enter Kodi settings instead
|
||||||
if dialog.yesno(
|
if dialog.yesno(
|
||||||
heading=self.addonName,
|
heading=self.addonName,
|
||||||
line1=string(39016)):
|
line1=string(39016).encode('utf-8')):
|
||||||
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")
|
||||||
xbmc.executebuiltin('Addon.OpenSettings(%s)' % self.addonId)
|
xbmc.executebuiltin('Addon.OpenSettings(%s)' % self.addonId)
|
||||||
|
@ -202,12 +209,12 @@ class InitialSetup():
|
||||||
|
|
||||||
if dialog.yesno(
|
if dialog.yesno(
|
||||||
heading=self.addonName,
|
heading=self.addonName,
|
||||||
line1=string(39016)):
|
line1=string(39016).encode('utf-8')):
|
||||||
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(
|
if dialog.yesno(
|
||||||
heading=self.addonName,
|
heading=self.addonName,
|
||||||
line1=string(39017)):
|
line1=string(39017).encode('utf-8')):
|
||||||
xbmc.executebuiltin(
|
xbmc.executebuiltin(
|
||||||
'Addon.OpenSettings(plugin.video.plexkodiconnect)')
|
'Addon.OpenSettings(plugin.video.plexkodiconnect)')
|
||||||
|
|
|
@ -164,10 +164,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.encode('utf-8'),
|
% (self.addonName,
|
||||||
self.itemType.encode('utf-8'),
|
self.itemType,
|
||||||
str(total)),
|
str(total))).encode('utf-8'),
|
||||||
"Starting")
|
"Starting")
|
||||||
global getMetadataCount
|
global getMetadataCount
|
||||||
global processMetadataCount
|
global processMetadataCount
|
||||||
|
@ -188,9 +188,9 @@ class ThreadedShowSyncInfo(Thread):
|
||||||
try:
|
try:
|
||||||
dialog.update(
|
dialog.update(
|
||||||
percentage,
|
percentage,
|
||||||
message="Downloaded: %s. Processed: %s: %s"
|
message=("Downloaded: %s. Processed: %s: %s"
|
||||||
% (getMetadataProgress, processMetadataProgress,
|
% (getMetadataProgress, processMetadataProgress,
|
||||||
viewName.decode('utf-8')))
|
viewName))).encode('utf-8')
|
||||||
except:
|
except:
|
||||||
# Wierd formating of the string viewName?!?
|
# Wierd formating of the string viewName?!?
|
||||||
pass
|
pass
|
||||||
|
@ -225,6 +225,9 @@ class LibrarySync(Thread):
|
||||||
utils.settings('dbSyncIndicator') == 'true' else False
|
utils.settings('dbSyncIndicator') == 'true' else False
|
||||||
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(
|
||||||
|
'enableBackgroundSync') == "true" \
|
||||||
|
else False
|
||||||
|
|
||||||
Thread.__init__(self)
|
Thread.__init__(self)
|
||||||
|
|
||||||
|
@ -236,7 +239,7 @@ class LibrarySync(Thread):
|
||||||
return
|
return
|
||||||
xbmcgui.Dialog().notification(
|
xbmcgui.Dialog().notification(
|
||||||
heading=self.addonName,
|
heading=self.addonName,
|
||||||
message=message,
|
message=message.encode('utf-8'),
|
||||||
icon="special://home/addons/plugin.video.plexkodiconnect/icon.png",
|
icon="special://home/addons/plugin.video.plexkodiconnect/icon.png",
|
||||||
sound=False)
|
sound=False)
|
||||||
|
|
||||||
|
@ -1253,7 +1256,7 @@ class LibrarySync(Thread):
|
||||||
time=3000,
|
time=3000,
|
||||||
sound=True)
|
sound=True)
|
||||||
window('emby_dbScan', clear=True)
|
window('emby_dbScan', clear=True)
|
||||||
else:
|
elif self.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
|
||||||
|
|
|
@ -214,7 +214,7 @@ def getSongTags(file):
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
#file in use ?
|
#file in use ?
|
||||||
logMsg("Exception in getSongTags %s" %e,0)
|
utils.logMsg("Exception in getSongTags", str(e),0)
|
||||||
rating = None
|
rating = None
|
||||||
|
|
||||||
#remove tempfile if needed....
|
#remove tempfile if needed....
|
||||||
|
|
|
@ -523,7 +523,10 @@ class Player(xbmc.Player):
|
||||||
# Plex: never delete
|
# Plex: never delete
|
||||||
offerDelete = False
|
offerDelete = False
|
||||||
if percentComplete >= markPlayedAt and offerDelete:
|
if percentComplete >= markPlayedAt and offerDelete:
|
||||||
resp = xbmcgui.Dialog().yesno(lang(30091), lang(33015), autoclose=120000)
|
resp = xbmcgui.Dialog().yesno(
|
||||||
|
lang(30091).encode('utf-8'),
|
||||||
|
lang(33015).encode('utf-8'),
|
||||||
|
autoclose=120000)
|
||||||
if not resp:
|
if not resp:
|
||||||
log("User skipped deletion.", 1)
|
log("User skipped deletion.", 1)
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -8,7 +8,6 @@ from urllib import urlencode
|
||||||
import xbmc
|
import xbmc
|
||||||
import xbmcgui
|
import xbmcgui
|
||||||
|
|
||||||
import playbackutils
|
|
||||||
import embydb_functions as embydb
|
import embydb_functions as embydb
|
||||||
import read_embyserver as embyserver
|
import read_embyserver as embyserver
|
||||||
import utils
|
import utils
|
||||||
|
|
|
@ -343,7 +343,7 @@ class PlayUtils():
|
||||||
|
|
||||||
#audioStreamsChannelsList[audioNum] = stream.attrib['channels']
|
#audioStreamsChannelsList[audioNum] = stream.attrib['channels']
|
||||||
audioStreamsList.append(index)
|
audioStreamsList.append(index)
|
||||||
audioStreams.append(track)
|
audioStreams.append(track.encode('utf-8'))
|
||||||
audioNum += 1
|
audioNum += 1
|
||||||
|
|
||||||
# Subtitles
|
# Subtitles
|
||||||
|
@ -367,11 +367,11 @@ class PlayUtils():
|
||||||
downloadableStreams.append(index)
|
downloadableStreams.append(index)
|
||||||
|
|
||||||
subtitleStreamsList.append(index)
|
subtitleStreamsList.append(index)
|
||||||
subtitleStreams.append(track)
|
subtitleStreams.append(track.encode('utf-8'))
|
||||||
subNum += 1
|
subNum += 1
|
||||||
|
|
||||||
if audioNum > 1:
|
if audioNum > 1:
|
||||||
resp = dialog.select(lang(33013), audioStreams)
|
resp = dialog.select(lang(33013).encode('utf-8'), audioStreams)
|
||||||
if resp > -1:
|
if resp > -1:
|
||||||
# User selected audio
|
# User selected audio
|
||||||
playurlprefs['audioStreamID'] = audioStreamsList[resp]
|
playurlprefs['audioStreamID'] = audioStreamsList[resp]
|
||||||
|
@ -384,7 +384,7 @@ class PlayUtils():
|
||||||
playurlprefs['audioBoost'] = utils.settings('audioBoost')
|
playurlprefs['audioBoost'] = utils.settings('audioBoost')
|
||||||
|
|
||||||
if subNum > 1:
|
if subNum > 1:
|
||||||
resp = dialog.select(lang(33014), subtitleStreams)
|
resp = dialog.select(lang(33014).encode('utf-8'), subtitleStreams)
|
||||||
if resp == 0:
|
if resp == 0:
|
||||||
# User selected no subtitles
|
# User selected no subtitles
|
||||||
playurlprefs["skipSubtitles"] = 1
|
playurlprefs["skipSubtitles"] = 1
|
||||||
|
|
|
@ -262,14 +262,14 @@ class Read_EmbyServer():
|
||||||
retry = 0
|
retry = 0
|
||||||
while utils.window('emby_online') != "true":
|
while utils.window('emby_online') != "true":
|
||||||
# Wait server to come back online
|
# Wait server to come back online
|
||||||
if retry == 3:
|
if retry == 5:
|
||||||
log("Unable to reconnect to server. Abort process.", 1)
|
log("Unable to reconnect to server. Abort process.", 1)
|
||||||
return
|
return items
|
||||||
|
|
||||||
retry += 1
|
retry += 1
|
||||||
if xbmc.Monitor().waitForAbort(1):
|
if xbmc.Monitor().waitForAbort(1):
|
||||||
# Abort was requested while waiting.
|
# Abort was requested while waiting.
|
||||||
return
|
return items
|
||||||
else:
|
else:
|
||||||
# Request succeeded
|
# Request succeeded
|
||||||
index += jump
|
index += jump
|
||||||
|
@ -321,18 +321,18 @@ class Read_EmbyServer():
|
||||||
# Filter view types
|
# Filter view types
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# 11/10/2015 Review key, when it's added to server. Currently unavailable.
|
# 3/4/2016 OriginalCollectionType is added
|
||||||
itemtype = item.get('OriginalCollectionType', item.get('CollectionType'))
|
itemtype = item.get('OriginalCollectionType', item.get('CollectionType', "mixed"))
|
||||||
|
|
||||||
# 11/29/2015 Remove this once OriginalCollectionType is added to stable server.
|
# 11/29/2015 Remove this once OriginalCollectionType is added to stable server.
|
||||||
# Assumed missing is mixed then.
|
# Assumed missing is mixed then.
|
||||||
if itemtype is None:
|
'''if itemtype is None:
|
||||||
url = "{server}/emby/Library/MediaFolders?format=json"
|
url = "{server}/emby/Library/MediaFolders?format=json"
|
||||||
result = doUtils(url)
|
result = doUtils(url)
|
||||||
|
|
||||||
for folder in result['Items']:
|
for folder in result['Items']:
|
||||||
if itemId == folder['Id']:
|
if itemId == folder['Id']:
|
||||||
itemtype = folder.get('CollectionType', "mixed")
|
itemtype = folder.get('CollectionType', "mixed")'''
|
||||||
|
|
||||||
if name not in ('Collections', 'Trailers'):
|
if name not in ('Collections', 'Trailers'):
|
||||||
|
|
||||||
|
|
|
@ -54,12 +54,15 @@ class UserClient(threading.Thread):
|
||||||
self.AdditionalUser = additionalUsers.split(',')
|
self.AdditionalUser = additionalUsers.split(',')
|
||||||
|
|
||||||
def getUsername(self):
|
def getUsername(self):
|
||||||
|
"""
|
||||||
|
Returns username as unicode
|
||||||
|
"""
|
||||||
|
|
||||||
username = utils.settings('username')
|
username = utils.settings('username').decode('utf-8')
|
||||||
|
|
||||||
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')
|
username = utils.settings('plexLogin').decode('utf-8')
|
||||||
if not username:
|
if not username:
|
||||||
self.logMsg("Also no Plex username found", 0)
|
self.logMsg("Also no Plex username found", 0)
|
||||||
return ""
|
return ""
|
||||||
|
@ -84,33 +87,31 @@ class UserClient(threading.Thread):
|
||||||
if username is None:
|
if username is None:
|
||||||
username = self.getUsername()
|
username = self.getUsername()
|
||||||
w_userId = window('emby_currUser')
|
w_userId = window('emby_currUser')
|
||||||
s_userId = settings('userId%s' % username)
|
s_userId = settings('userId')
|
||||||
|
|
||||||
# Verify the window property
|
# Verify the window property
|
||||||
if w_userId:
|
if w_userId:
|
||||||
if not s_userId:
|
if not s_userId:
|
||||||
# Save access token if it's missing from settings
|
# Save access token if it's missing from settings
|
||||||
settings('userId%s' % username, value=w_userId)
|
settings('userId', value=w_userId)
|
||||||
log("Returning userId from WINDOW for username: %s UserId: %s"
|
log("Returning userId %s from WINDOW for username %s"
|
||||||
% (username, w_userId), 1)
|
% (w_userId, username), 0)
|
||||||
return w_userId
|
return w_userId
|
||||||
# Verify the settings
|
# Verify the settings
|
||||||
elif s_userId:
|
elif s_userId:
|
||||||
log("Returning userId from SETTINGS for username: %s userId: %s"
|
log("Returning userId %s from SETTINGS for username %s"
|
||||||
% (username, s_userId), 1)
|
% (w_userId, username), 0)
|
||||||
return s_userId
|
return s_userId
|
||||||
# No userId found
|
# No userId found
|
||||||
else:
|
log("No userId saved. Trying to get Plex to use instead", 0)
|
||||||
log("No userId saved for username: %s. Trying to get Plex ID"
|
plexId = settings('plexid')
|
||||||
% username, 0)
|
if not plexId:
|
||||||
plexId = settings('plexid')
|
log('Also no Plex ID found in settings', 0)
|
||||||
if not plexId:
|
return ''
|
||||||
log('Also no Plex ID found in settings', 0)
|
log('Using Plex ID %s as userid for username %s'
|
||||||
return ''
|
% (plexId, username), 0)
|
||||||
log('Using Plex ID %s as userid for username: %s'
|
settings('userId', value=plexId)
|
||||||
% (plexId, username))
|
return plexId
|
||||||
settings('userId%s' % username, value=plexId)
|
|
||||||
return plexId
|
|
||||||
|
|
||||||
def getServer(self, prefix=True):
|
def getServer(self, prefix=True):
|
||||||
|
|
||||||
|
@ -157,14 +158,14 @@ class UserClient(threading.Thread):
|
||||||
if not s_token:
|
if not s_token:
|
||||||
# Save access token if it's missing from settings
|
# Save access token if it's missing from settings
|
||||||
settings('accessToken', value=w_token)
|
settings('accessToken', value=w_token)
|
||||||
log("Returning accessToken from WINDOW for username: %s accessToken: %s"
|
log("Returning accessToken from WINDOW for username: %s "
|
||||||
% (username, w_token), 2)
|
"accessToken: xxxx" % username, 2)
|
||||||
return w_token
|
return w_token
|
||||||
# Verify the settings
|
# Verify the settings
|
||||||
elif s_token:
|
elif s_token:
|
||||||
log("Returning accessToken from SETTINGS for username: %s accessToken: %s"
|
log("Returning accessToken from SETTINGS for username: %s "
|
||||||
% (username, s_token), 2)
|
"accessToken: xxxx" % username, 2)
|
||||||
window('emby_accessToken%s' % username, value=s_token)
|
window('emby_accessToken%s' % userId, value=s_token)
|
||||||
return s_token
|
return s_token
|
||||||
else:
|
else:
|
||||||
log("No token found.", 1)
|
log("No token found.", 1)
|
||||||
|
@ -244,7 +245,9 @@ 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(self.addonName, utils.language(33007))
|
xbmcgui.Dialog().notification(
|
||||||
|
self.addonName,
|
||||||
|
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)
|
||||||
|
@ -284,7 +287,6 @@ class UserClient(threading.Thread):
|
||||||
window('plex_username', value=username)
|
window('plex_username', value=username)
|
||||||
window('emby_accessToken%s' % userId, value=self.currToken)
|
window('emby_accessToken%s' % userId, value=self.currToken)
|
||||||
window('emby_server%s' % userId, value=self.currServer)
|
window('emby_server%s' % userId, value=self.currServer)
|
||||||
window('emby_server_%s' % userId, value=self.getServer(prefix=False))
|
|
||||||
window('plex_machineIdentifier', value=self.machineIdentifier)
|
window('plex_machineIdentifier', value=self.machineIdentifier)
|
||||||
|
|
||||||
window('emby_serverStatus', clear=True)
|
window('emby_serverStatus', clear=True)
|
||||||
|
@ -359,9 +361,8 @@ class UserClient(threading.Thread):
|
||||||
# Check connection
|
# Check connection
|
||||||
if plx.CheckConnection(server, accessToken) == 200:
|
if plx.CheckConnection(server, accessToken) == 200:
|
||||||
self.currUser = username
|
self.currUser = username
|
||||||
dialog = xbmcgui.Dialog()
|
|
||||||
settings('accessToken', value=accessToken)
|
settings('accessToken', value=accessToken)
|
||||||
settings('userId%s' % username, value=userId)
|
settings('userId', value=userId)
|
||||||
log("User authenticated with an access token", 1)
|
log("User authenticated with an access token", 1)
|
||||||
if self.loadCurrUser(authenticated=True) is False:
|
if self.loadCurrUser(authenticated=True) is False:
|
||||||
# Something went really wrong, return and try again
|
# Something went really wrong, return and try again
|
||||||
|
@ -372,7 +373,7 @@ class UserClient(threading.Thread):
|
||||||
if username:
|
if username:
|
||||||
dialog.notification(
|
dialog.notification(
|
||||||
heading=self.addonName,
|
heading=self.addonName,
|
||||||
message="Welcome %s" % username.decode('utf-8'),
|
message=("Welcome " + username).encode('utf-8'),
|
||||||
icon="special://home/addons/plugin.video.plexkodiconnect/icon.png")
|
icon="special://home/addons/plugin.video.plexkodiconnect/icon.png")
|
||||||
else:
|
else:
|
||||||
dialog.notification(
|
dialog.notification(
|
||||||
|
@ -384,13 +385,14 @@ class UserClient(threading.Thread):
|
||||||
else:
|
else:
|
||||||
self.logMsg("Error: user authentication failed.", -1)
|
self.logMsg("Error: user authentication failed.", -1)
|
||||||
settings('accessToken', value="")
|
settings('accessToken', value="")
|
||||||
settings('userId%s' % username, 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 >= 5:
|
||||||
log("Too many retries.", 1)
|
log("Too many retries.", 1)
|
||||||
window('emby_serverStatus', value="Stop")
|
window('emby_serverStatus', value="Stop")
|
||||||
dialog.ok(lang(33001), lang(39023))
|
dialog.ok(lang(33001).encode('utf-8'),
|
||||||
|
lang(39023).encode('utf-8'))
|
||||||
xbmc.executebuiltin(
|
xbmc.executebuiltin(
|
||||||
'Addon.OpenSettings(plugin.video.plexkodiconnect)')
|
'Addon.OpenSettings(plugin.video.plexkodiconnect)')
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,27 @@ import xbmcvfs
|
||||||
addonName = xbmcaddon.Addon().getAddonInfo('name')
|
addonName = xbmcaddon.Addon().getAddonInfo('name')
|
||||||
|
|
||||||
|
|
||||||
|
def IfExists(path):
|
||||||
|
"""
|
||||||
|
Kodi's xbmcvfs.exists is broken - it caches the results for directories.
|
||||||
|
|
||||||
|
path: path to a directory (with a slash at the end)
|
||||||
|
|
||||||
|
Returns True if path exists, else false
|
||||||
|
"""
|
||||||
|
dummyfile = os.path.join(path, 'dummyfile.txt').encode('utf-8')
|
||||||
|
try:
|
||||||
|
etree.ElementTree(etree.Element('test')).write(dummyfile)
|
||||||
|
except:
|
||||||
|
# folder does not exist yet
|
||||||
|
answer = False
|
||||||
|
else:
|
||||||
|
# Folder exists. Delete file again.
|
||||||
|
xbmcvfs.delete(dummyfile)
|
||||||
|
answer = True
|
||||||
|
return answer
|
||||||
|
|
||||||
|
|
||||||
def LogTime(func):
|
def LogTime(func):
|
||||||
"""
|
"""
|
||||||
Decorator for functions and methods to log the time it took to run the code
|
Decorator for functions and methods to log the time it took to run the code
|
||||||
|
@ -207,18 +228,26 @@ 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)
|
WINDOW.setProperty(property, value)
|
||||||
else: #getproperty returns string so convert to unicode
|
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.
|
||||||
|
|
||||||
|
Settings needs to be string
|
||||||
|
Value can either be unicode or string
|
||||||
|
"""
|
||||||
addon = xbmcaddon.Addon(id='plugin.video.plexkodiconnect')
|
addon = xbmcaddon.Addon(id='plugin.video.plexkodiconnect')
|
||||||
|
|
||||||
if value is not None:
|
if value is not None:
|
||||||
|
# Takes string or unicode by default!
|
||||||
addon.setSetting(setting, value)
|
addon.setSetting(setting, value)
|
||||||
else:
|
else:
|
||||||
return addon.getSetting(setting) #returns unicode object
|
# Returns unicode by default!
|
||||||
|
return addon.getSetting(setting)
|
||||||
|
|
||||||
def language(stringid):
|
def language(stringid):
|
||||||
# Central string retrieval
|
# Central string retrieval
|
||||||
|
@ -410,8 +439,8 @@ def reset():
|
||||||
addon = xbmcaddon.Addon()
|
addon = xbmcaddon.Addon()
|
||||||
addondir = xbmc.translatePath(addon.getAddonInfo('profile')).decode('utf-8')
|
addondir = xbmc.translatePath(addon.getAddonInfo('profile')).decode('utf-8')
|
||||||
dataPath = "%ssettings.xml" % addondir
|
dataPath = "%ssettings.xml" % addondir
|
||||||
xbmcvfs.delete(dataPath)
|
xbmcvfs.delete(dataPath.encode('utf-8'))
|
||||||
logMsg("EMBY", "Deleting: settings.xml", 1)
|
logMsg("PLEX", "Deleting: settings.xml", 1)
|
||||||
|
|
||||||
dialog.ok(
|
dialog.ok(
|
||||||
heading="Emby for Kodi",
|
heading="Emby for Kodi",
|
||||||
|
@ -668,9 +697,9 @@ def passwordsXML():
|
||||||
sound=False)
|
sound=False)
|
||||||
|
|
||||||
def playlistXSP(mediatype, tagname, viewid, viewtype="", delete=False):
|
def playlistXSP(mediatype, tagname, viewid, viewtype="", delete=False):
|
||||||
# Tagname is in unicode - actions: add or delete
|
"""
|
||||||
tagname = tagname.encode('utf-8')
|
Feed with tagname as unicode
|
||||||
|
"""
|
||||||
path = xbmc.translatePath("special://profile/playlists/video/").decode('utf-8')
|
path = xbmc.translatePath("special://profile/playlists/video/").decode('utf-8')
|
||||||
if viewtype == "mixed":
|
if viewtype == "mixed":
|
||||||
plname = "%s - %s" % (tagname, mediatype)
|
plname = "%s - %s" % (tagname, mediatype)
|
||||||
|
@ -680,15 +709,15 @@ def playlistXSP(mediatype, tagname, viewid, viewtype="", delete=False):
|
||||||
xsppath = "%sPlex %s.xsp" % (path, viewid)
|
xsppath = "%sPlex %s.xsp" % (path, viewid)
|
||||||
|
|
||||||
# Create the playlist directory
|
# Create the playlist directory
|
||||||
if not xbmcvfs.exists(path):
|
if not xbmcvfs.exists(path.encode('utf-8')):
|
||||||
logMsg("PLEX", "Creating directory: %s" % path, 1)
|
logMsg("PLEX", "Creating directory: %s" % path, 1)
|
||||||
xbmcvfs.mkdirs(path)
|
xbmcvfs.mkdirs(path.encode('utf-8'))
|
||||||
|
|
||||||
# Only add the playlist if it doesn't already exists
|
# Only add the playlist if it doesn't already exists
|
||||||
if xbmcvfs.exists(xsppath):
|
if xbmcvfs.exists(xsppath.encode('utf-8')):
|
||||||
|
logMsg('Path %s does exist' % xsppath, 1)
|
||||||
if delete:
|
if delete:
|
||||||
xbmcvfs.delete(xsppath)
|
xbmcvfs.delete(xsppath.encode('utf-8'))
|
||||||
logMsg("PLEX", "Successfully removed playlist: %s." % tagname, 1)
|
logMsg("PLEX", "Successfully removed playlist: %s." % tagname, 1)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -699,21 +728,22 @@ def playlistXSP(mediatype, tagname, viewid, viewtype="", delete=False):
|
||||||
}
|
}
|
||||||
logMsg("Plex", "Writing playlist file to: %s" % xsppath, 1)
|
logMsg("Plex", "Writing playlist file to: %s" % xsppath, 1)
|
||||||
try:
|
try:
|
||||||
f = xbmcvfs.File(xsppath, 'w')
|
f = xbmcvfs.File(xsppath.encode('utf-8'), 'wb')
|
||||||
except:
|
except:
|
||||||
logMsg("Plex", "Failed to create playlist: %s" % xsppath, -1)
|
logMsg("Plex", "Failed to create playlist: %s" % xsppath, -1)
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
f.write(
|
f.write((
|
||||||
'<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>\n'
|
'<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>\n'
|
||||||
'<smartplaylist type="%s">\n\t'
|
'<smartplaylist type="%s">\n\t'
|
||||||
'<name>Plex %s</name>\n\t'
|
'<name>Plex %s</name>\n\t'
|
||||||
'<match>all</match>\n\t'
|
'<match>all</match>\n\t'
|
||||||
'<rule field="tag" operator="is">\n\t\t'
|
'<rule field="tag" operator="is">\n\t\t'
|
||||||
'<value>%s</value>\n\t'
|
'<value>%s</value>\n\t'
|
||||||
'</rule>'
|
'</rule>\n'
|
||||||
'</smartplaylist>'
|
'</smartplaylist>'
|
||||||
% (itemtypes.get(mediatype, mediatype), plname, tagname))
|
% (itemtypes.get(mediatype, mediatype), plname, tagname))
|
||||||
|
.encode('utf-8'))
|
||||||
f.close()
|
f.close()
|
||||||
logMsg("Plex", "Successfully added playlist: %s" % tagname)
|
logMsg("Plex", "Successfully added playlist: %s" % tagname)
|
||||||
|
|
||||||
|
@ -721,26 +751,26 @@ def deletePlaylists():
|
||||||
|
|
||||||
# Clean up the playlists
|
# Clean up the playlists
|
||||||
path = xbmc.translatePath("special://profile/playlists/video/").decode('utf-8')
|
path = xbmc.translatePath("special://profile/playlists/video/").decode('utf-8')
|
||||||
dirs, files = xbmcvfs.listdir(path)
|
dirs, files = xbmcvfs.listdir(path.encode('utf-8'))
|
||||||
for file in files:
|
for file in files:
|
||||||
if file.decode('utf-8').startswith('Emby'):
|
if file.decode('utf-8').startswith('Plex'):
|
||||||
xbmcvfs.delete("%s%s" % (path, file))
|
xbmcvfs.delete(("%s%s" % (path, file.decode('utf-8'))).encode('utf-8'))
|
||||||
|
|
||||||
def deleteNodes():
|
def deleteNodes():
|
||||||
|
|
||||||
# Clean up video nodes
|
# Clean up video nodes
|
||||||
import shutil
|
import shutil
|
||||||
path = xbmc.translatePath("special://profile/library/video/").decode('utf-8')
|
path = xbmc.translatePath("special://profile/library/video/").decode('utf-8')
|
||||||
dirs, files = xbmcvfs.listdir(path)
|
dirs, files = xbmcvfs.listdir(path.encode('utf-8'))
|
||||||
for dir in dirs:
|
for dir in dirs:
|
||||||
if dir.decode('utf-8').startswith('Emby'):
|
if dir.decode('utf-8').startswith('Plex'):
|
||||||
try:
|
try:
|
||||||
shutil.rmtree("%s%s" % (path, dir.decode('utf-8')))
|
shutil.rmtree("%s%s" % (path, dir.decode('utf-8')))
|
||||||
except:
|
except:
|
||||||
logMsg("EMBY", "Failed to delete directory: %s" % dir.decode('utf-8'))
|
logMsg("PLEX", "Failed to delete directory: %s" % dir.decode('utf-8'))
|
||||||
for file in files:
|
for file in files:
|
||||||
if file.decode('utf-8').startswith('emby'):
|
if file.decode('utf-8').startswith('plex'):
|
||||||
try:
|
try:
|
||||||
xbmcvfs.delete("%s%s" % (path, file.decode('utf-8')))
|
xbmcvfs.delete(("%s%s" % (path, file.decode('utf-8'))).encode('utf-8'))
|
||||||
except:
|
except:
|
||||||
logMsg("EMBY", "Failed to file: %s" % file.decode('utf-8'))
|
logMsg("PLEX", "Failed to file: %s" % file.decode('utf-8'))
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
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
|
||||||
|
@ -41,7 +42,6 @@ class VideoNodes(object):
|
||||||
return root
|
return root
|
||||||
|
|
||||||
def viewNode(self, indexnumber, tagname, mediatype, viewtype, viewid, delete=False):
|
def viewNode(self, indexnumber, tagname, mediatype, viewtype, viewid, delete=False):
|
||||||
|
|
||||||
# Plex: reassign mediatype due to Kodi inner workings
|
# Plex: reassign mediatype due to Kodi inner workings
|
||||||
mediatypes = {
|
mediatypes = {
|
||||||
'movie': 'movies',
|
'movie': 'movies',
|
||||||
|
@ -65,24 +65,29 @@ class VideoNodes(object):
|
||||||
"special://profile/library/video/Plex-%s/" % dirname).decode('utf-8')
|
"special://profile/library/video/Plex-%s/" % dirname).decode('utf-8')
|
||||||
|
|
||||||
# Verify the video directory
|
# Verify the video directory
|
||||||
if not xbmcvfs.exists(path):
|
# KODI BUG
|
||||||
|
# Kodi caches the result of exists for directories
|
||||||
|
# so try creating a file
|
||||||
|
if utils.IfExists(path) is False:
|
||||||
shutil.copytree(
|
shutil.copytree(
|
||||||
src=xbmc.translatePath("special://xbmc/system/library/video").decode('utf-8'),
|
src=xbmc.translatePath("special://xbmc/system/library/video").decode('utf-8'),
|
||||||
dst=xbmc.translatePath("special://profile/library/video").decode('utf-8'))
|
dst=xbmc.translatePath("special://profile/library/video").decode('utf-8'))
|
||||||
xbmcvfs.exists(path)
|
|
||||||
|
|
||||||
# Create the node directory
|
# Create the node directory
|
||||||
if not xbmcvfs.exists(nodepath) and not mediatype == "photo":
|
if mediatype != "photo":
|
||||||
# We need to copy over the default items
|
if utils.IfExists(nodepath) is False:
|
||||||
xbmcvfs.mkdirs(nodepath)
|
# folder does not exist yet
|
||||||
else:
|
self.logMsg('Creating folder %s' % nodepath, 1)
|
||||||
if delete:
|
xbmcvfs.mkdirs(nodepath.encode('utf-8'))
|
||||||
dirs, files = xbmcvfs.listdir(nodepath)
|
if delete:
|
||||||
for file in files:
|
dirs, files = xbmcvfs.listdir(nodepath.encode('utf-8'))
|
||||||
xbmcvfs.delete(nodepath + file)
|
for file in files:
|
||||||
|
xbmcvfs.delete(
|
||||||
|
(nodepath + file.decode('utf-8')).encode('utf-8'))
|
||||||
|
|
||||||
self.logMsg("Sucessfully removed videonode: %s." % tagname, 1)
|
self.logMsg("Sucessfully removed videonode: %s."
|
||||||
return
|
% tagname, 1)
|
||||||
|
return
|
||||||
|
|
||||||
# Create index entry
|
# Create index entry
|
||||||
nodeXML = "%sindex.xml" % nodepath
|
nodeXML = "%sindex.xml" % nodepath
|
||||||
|
@ -239,7 +244,7 @@ class VideoNodes(object):
|
||||||
# To do: add our photos nodes to kodi picture sources somehow
|
# To do: add our photos nodes to kodi picture sources somehow
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if xbmcvfs.exists(nodeXML):
|
if xbmcvfs.exists(nodeXML.encode('utf-8')):
|
||||||
# Don't recreate xml if already exists
|
# Don't recreate xml if already exists
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,7 @@
|
||||||
<setting id="syncEmptyShows" type="bool" label="30508" default="false" visible="false"/>
|
<setting id="syncEmptyShows" type="bool" label="30508" default="false" visible="false"/>
|
||||||
<setting id="useDirectPaths" type="enum" label="30511" values="Addon(Default)|Native(Direct paths)" default="0" visible="false"/> <!-- Playback mode -->
|
<setting id="useDirectPaths" type="enum" label="30511" values="Addon(Default)|Native(Direct paths)" default="0" visible="false"/> <!-- Playback mode -->
|
||||||
<setting id="enableMusic" type="bool" label="30509" default="true" />
|
<setting id="enableMusic" type="bool" label="30509" default="true" />
|
||||||
|
<setting id="enableBackgroundSync" type="bool" label="39026" default="true" visible="true"/>
|
||||||
<setting id="streamMusic" type="bool" label="30510" default="false" visible="false" subsetting="true"/> <!-- Direct stream Music library -->
|
<setting id="streamMusic" type="bool" label="30510" default="false" visible="false" subsetting="true"/> <!-- Direct stream Music library -->
|
||||||
<setting type="lsep" label="30523" visible="false"/> <!-- Music metadata options -->
|
<setting type="lsep" label="30523" visible="false"/> <!-- Music metadata options -->
|
||||||
<setting id="enableImportSongRating" type="bool" label="30524" default="true" visible="false"/>
|
<setting id="enableImportSongRating" type="bool" label="30524" default="true" visible="false"/>
|
||||||
|
|
11
service.py
11
service.py
|
@ -171,9 +171,8 @@ 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"
|
message=("%s %s" % (lang(33000), user.currUser)
|
||||||
% (lang(33000),
|
).encode('utf-8'),
|
||||||
user.currUser.decode('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)
|
||||||
|
@ -226,8 +225,8 @@ class Service():
|
||||||
window('emby_online', value="false")
|
window('emby_online', value="false")
|
||||||
|
|
||||||
xbmcgui.Dialog().notification(
|
xbmcgui.Dialog().notification(
|
||||||
heading=lang(33001),
|
heading=lang(33001).encode('utf-8'),
|
||||||
message="%s %s" % (self.addonName, lang(33002)),
|
message=("%s %s" % (self.addonName, lang(33002))).encode('utf-8'),
|
||||||
icon="special://home/addons/plugin.video."
|
icon="special://home/addons/plugin.video."
|
||||||
"plexkodiconnect/icon.png",
|
"plexkodiconnect/icon.png",
|
||||||
sound=False)
|
sound=False)
|
||||||
|
@ -245,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),
|
message=lang(33003).encode('utf-8'),
|
||||||
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