Fix for Windows usernames with non-ASCII chars

- Fixes #286
This commit is contained in:
tomkat83 2017-05-20 20:24:47 +02:00
parent b0d1fcfe8a
commit ad5744f435
8 changed files with 76 additions and 75 deletions

View file

@ -2553,14 +2553,14 @@ class API():
if "\\" in path: if "\\" in path:
if not path.endswith('\\'): if not path.endswith('\\'):
# Add the missing backslash # Add the missing backslash
check = exists_dir(tryEncode(path + "\\")) check = exists_dir(path + "\\")
else: else:
check = exists_dir(tryEncode(path)) check = exists_dir(path)
else: else:
if not path.endswith('/'): if not path.endswith('/'):
check = exists_dir(tryEncode(path + "/")) check = exists_dir(path + "/")
else: else:
check = exists_dir(tryEncode(path)) check = exists_dir(path)
if not check: if not check:
if forceCheck is False: if forceCheck is False:

View file

@ -13,7 +13,7 @@ from xbmc import executeJSONRPC, sleep, translatePath
from xbmcvfs import exists from xbmcvfs import exists
from utils import window, settings, language as lang, kodiSQL, tryEncode, \ from utils import window, settings, language as lang, kodiSQL, tryEncode, \
thread_methods, dialog, exists_dir thread_methods, dialog, exists_dir, tryDecode
# Disable annoying requests warnings # Disable annoying requests warnings
import requests.packages.urllib3 import requests.packages.urllib3
@ -222,7 +222,7 @@ class Artwork():
if dialog('yesno', "Image Texture Cache", lang(39251)): if dialog('yesno', "Image Texture Cache", lang(39251)):
log.info("Resetting all cache data first") log.info("Resetting all cache data first")
# Remove all existing textures first # Remove all existing textures first
path = translatePath("special://thumbnails/") path = tryDecode(translatePath("special://thumbnails/"))
if exists_dir(path): if exists_dir(path):
rmtree(path, ignore_errors=True) rmtree(path, ignore_errors=True)
@ -423,7 +423,7 @@ class Artwork():
path = translatePath("special://thumbnails/%s" % cachedurl) path = translatePath("special://thumbnails/%s" % cachedurl)
log.debug("Deleting cached thumbnail: %s" % path) log.debug("Deleting cached thumbnail: %s" % path)
if exists(path): if exists(path):
rmtree(path, ignore_errors=True) rmtree(tryDecode(path), ignore_errors=True)
cursor.execute("DELETE FROM texture WHERE url = ?", (url,)) cursor.execute("DELETE FROM texture WHERE url = ?", (url,))
connection.commit() connection.commit()
finally: finally:

View file

@ -12,7 +12,7 @@ from xbmc import sleep, executebuiltin, translatePath
from xbmcgui import ListItem from xbmcgui import ListItem
from utils import window, settings, language as lang, dialog, tryEncode, \ from utils import window, settings, language as lang, dialog, tryEncode, \
CatchExceptions, JSONRPC, exists_dir, plex_command CatchExceptions, JSONRPC, exists_dir, plex_command, tryDecode
import downloadutils import downloadutils
from PlexFunctions import GetPlexMetadata, GetPlexSectionResults, \ from PlexFunctions import GetPlexMetadata, GetPlexSectionResults, \
@ -489,7 +489,6 @@ def getVideoFiles(plexId, params):
except: except:
log.error('Could not get file path for item %s' % plexId) log.error('Could not get file path for item %s' % plexId)
return xbmcplugin.endOfDirectory(HANDLE) return xbmcplugin.endOfDirectory(HANDLE)
path = tryEncode(path)
# Assign network protocol # Assign network protocol
if path.startswith('\\\\'): if path.startswith('\\\\'):
path = path.replace('\\\\', 'smb://') path = path.replace('\\\\', 'smb://')
@ -502,14 +501,14 @@ def getVideoFiles(plexId, params):
if exists_dir(path): if exists_dir(path):
for root, dirs, files in walk(path): for root, dirs, files in walk(path):
for directory in dirs: for directory in dirs:
item_path = join(root, directory) item_path = tryEncode(join(root, directory))
li = ListItem(item_path, path=item_path) li = ListItem(item_path, path=item_path)
xbmcplugin.addDirectoryItem(handle=HANDLE, xbmcplugin.addDirectoryItem(handle=HANDLE,
url=item_path, url=item_path,
listitem=li, listitem=li,
isFolder=True) isFolder=True)
for file in files: for file in files:
item_path = join(root, file) item_path = tryEncode(join(root, file))
li = ListItem(item_path, path=item_path) li = ListItem(item_path, path=item_path)
xbmcplugin.addDirectoryItem(handle=HANDLE, xbmcplugin.addDirectoryItem(handle=HANDLE,
url=file, url=file,
@ -537,7 +536,8 @@ def getExtraFanArt(plexid, plexPath):
# We need to store the images locally for this to work # We need to store the images locally for this to work
# because of the caching system in xbmc # because of the caching system in xbmc
fanartDir = translatePath("special://thumbnails/plex/%s/" % plexid) fanartDir = tryDecode(translatePath(
"special://thumbnails/plex/%s/" % plexid))
if not exists_dir(fanartDir): if not exists_dir(fanartDir):
# Download the images to the cache directory # Download the images to the cache directory
makedirs(fanartDir) makedirs(fanartDir)
@ -550,19 +550,19 @@ def getExtraFanArt(plexid, plexPath):
backdrops = api.getAllArtwork()['Backdrop'] backdrops = api.getAllArtwork()['Backdrop']
for count, backdrop in enumerate(backdrops): for count, backdrop in enumerate(backdrops):
# Same ordering as in artwork # Same ordering as in artwork
fanartFile = join(fanartDir, "fanart%.3d.jpg" % count) fanartFile = tryEncode(join(fanartDir, "fanart%.3d.jpg" % count))
li = ListItem("%.3d" % count, path=fanartFile) li = ListItem("%.3d" % count, path=fanartFile)
xbmcplugin.addDirectoryItem( xbmcplugin.addDirectoryItem(
handle=HANDLE, handle=HANDLE,
url=fanartFile, url=fanartFile,
listitem=li) listitem=li)
copyfile(backdrop, fanartFile) copyfile(backdrop, tryDecode(fanartFile))
else: else:
log.info("Found cached backdrop.") log.info("Found cached backdrop.")
# Use existing cached images # Use existing cached images
for root, dirs, files in walk(fanartDir): for root, dirs, files in walk(fanartDir):
for file in files: for file in files:
fanartFile = join(root, file) fanartFile = tryEncode(join(root, file))
li = ListItem(file, path=fanartFile) li = ListItem(file, path=fanartFile)
xbmcplugin.addDirectoryItem(handle=HANDLE, xbmcplugin.addDirectoryItem(handle=HANDLE,
url=fanartFile, url=fanartFile,

View file

@ -12,7 +12,7 @@ from xbmcvfs import exists
from utils import window, settings, getUnixTimestamp, sourcesXML,\ from utils import window, settings, getUnixTimestamp, sourcesXML,\
thread_methods, create_actor_db_index, dialog, LogTime, getScreensaver,\ thread_methods, create_actor_db_index, dialog, LogTime, getScreensaver,\
setScreensaver, playlistXSP, language as lang, DateToKodi, reset,\ setScreensaver, playlistXSP, language as lang, DateToKodi, reset,\
tryDecode, deletePlaylists, deleteNodes tryDecode, deletePlaylists, deleteNodes, tryEncode
import downloadutils import downloadutils
import itemtypes import itemtypes
import plexdb_functions as plexdb import plexdb_functions as plexdb
@ -1507,7 +1507,7 @@ class LibrarySync(Thread):
# Also runs when first installed # Also runs when first installed
# Verify the video database can be found # Verify the video database can be found
videoDb = v.DB_VIDEO_PATH videoDb = v.DB_VIDEO_PATH
if not exists(videoDb): if not exists(tryEncode(videoDb)):
# Database does not exists # Database does not exists
log.error("The current Kodi version is incompatible " log.error("The current Kodi version is incompatible "
"to know which Kodi versions are supported.") "to know which Kodi versions are supported.")

View file

@ -111,12 +111,12 @@ def exists_dir(path):
Safe way to check whether the directory path exists already (broken in Kodi Safe way to check whether the directory path exists already (broken in Kodi
<17) <17)
Feed with encoded string Feed with encoded string or unicode
""" """
if KODIVERSION >= 17: if KODIVERSION >= 17:
answ = exists(path) answ = exists(tryEncode(path))
else: else:
dummyfile = join(path, 'dummyfile.txt') dummyfile = join(tryDecode(path), 'dummyfile.txt')
try: try:
with open(dummyfile, 'w') as f: with open(dummyfile, 'w') as f:
f.write('text') f.write('text')
@ -125,7 +125,7 @@ def exists_dir(path):
answ = 0 answ = 0
else: else:
# Folder exists. Delete file again. # Folder exists. Delete file again.
delete(dummyfile) delete(tryEncode(dummyfile))
answ = 1 answ = 1
return answ return answ
@ -401,7 +401,7 @@ def reset():
# Remove all existing textures first # Remove all existing textures first
path = xbmc.translatePath("special://thumbnails/") path = xbmc.translatePath("special://thumbnails/")
if exists(path): if exists(path):
rmtree(path, ignore_errors=True) rmtree(tryDecode(path), ignore_errors=True)
# remove all existing data from texture DB # remove all existing data from texture DB
connection = kodiSQL('texture') connection = kodiSQL('texture')
cursor = connection.cursor() cursor = connection.cursor()
@ -425,7 +425,7 @@ def reset():
line1=language(39603)): line1=language(39603)):
# Delete the settings # Delete the settings
addon = xbmcaddon.Addon() addon = xbmcaddon.Addon()
addondir = xbmc.translatePath(addon.getAddonInfo('profile')) addondir = tryDecode(xbmc.translatePath(addon.getAddonInfo('profile')))
dataPath = "%ssettings.xml" % addondir dataPath = "%ssettings.xml" % addondir
log.info("Deleting: settings.xml") log.info("Deleting: settings.xml")
remove(dataPath) remove(dataPath)
@ -688,7 +688,7 @@ def sourcesXML():
def passwordsXML(): def passwordsXML():
# To add network credentials # To add network credentials
path = xbmc.translatePath("special://userdata/") path = tryDecode(xbmc.translatePath("special://userdata/"))
xmlpath = "%spasswords.xml" % path xmlpath = "%spasswords.xml" % path
try: try:
@ -801,7 +801,7 @@ def playlistXSP(mediatype, tagname, viewid, viewtype="", delete=False):
""" """
Feed with tagname as unicode Feed with tagname as unicode
""" """
path = xbmc.translatePath("special://profile/playlists/video/") path = tryDecode(xbmc.translatePath("special://profile/playlists/video/"))
if viewtype == "mixed": if viewtype == "mixed":
plname = "%s - %s" % (tagname, mediatype) plname = "%s - %s" % (tagname, mediatype)
xsppath = "%sPlex %s - %s.xsp" % (path, viewid, mediatype) xsppath = "%sPlex %s - %s.xsp" % (path, viewid, mediatype)
@ -810,12 +810,12 @@ 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 exists(path): if not exists(tryEncode(path)):
log.info("Creating directory: %s" % path) log.info("Creating directory: %s" % path)
makedirs(path) makedirs(path)
# Only add the playlist if it doesn't already exists # Only add the playlist if it doesn't already exists
if exists(xsppath): if exists(tryEncode(xsppath)):
log.info('Path %s does exist' % xsppath) log.info('Path %s does exist' % xsppath)
if delete: if delete:
remove(xsppath) remove(xsppath)
@ -830,28 +830,22 @@ def playlistXSP(mediatype, tagname, viewid, viewtype="", delete=False):
'show': 'tvshows' 'show': 'tvshows'
} }
log.info("Writing playlist file to: %s" % xsppath) log.info("Writing playlist file to: %s" % xsppath)
try: with open(xsppath, 'wb'):
with open(xsppath, 'wb'): tryEncode(
tryEncode( '<?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>\n'
'</rule>\n' '</smartplaylist>\n'
'</smartplaylist>\n' % (itemtypes.get(mediatype, mediatype), plname, tagname))
% (itemtypes.get(mediatype, mediatype), plname, tagname))
except Exception as e:
log.error("Failed to create playlist: %s" % xsppath)
import traceback
log.exception("Traceback:\n%s" % traceback.format_exc())
return
log.info("Successfully added playlist: %s" % tagname) log.info("Successfully added playlist: %s" % tagname)
def deletePlaylists(): def deletePlaylists():
# Clean up the playlists # Clean up the playlists
path = xbmc.translatePath("special://profile/playlists/video/") path = tryDecode(xbmc.translatePath("special://profile/playlists/video/"))
for root, _, files in walk(path): for root, _, files in walk(path):
for file in files: for file in files:
if file.startswith('Plex'): if file.startswith('Plex'):
@ -859,7 +853,7 @@ def deletePlaylists():
def deleteNodes(): def deleteNodes():
# Clean up video nodes # Clean up video nodes
path = xbmc.translatePath("special://profile/library/video/") path = tryDecode(xbmc.translatePath("special://profile/library/video/"))
for root, dirs, _ in walk(path): for root, dirs, _ in walk(path):
for directory in dirs: for directory in dirs:
if directory.startswith('Plex-'): if directory.startswith('Plex-'):

View file

@ -2,7 +2,8 @@
import xbmc import xbmc
from xbmcaddon import Addon from xbmcaddon import Addon
# Paths are in string, not unicode! # Paths are in unicode, otherwise Windows will throw fits
# For any file operations with KODI function, use encoded strings!
def tryDecode(string, encoding='utf-8'): def tryDecode(string, encoding='utf-8'):
@ -29,7 +30,7 @@ ADDON_VERSION = _ADDON.getAddonInfo('version')
KODILANGUAGE = xbmc.getLanguage(xbmc.ISO_639_1) KODILANGUAGE = xbmc.getLanguage(xbmc.ISO_639_1)
KODIVERSION = int(xbmc.getInfoLabel("System.BuildVersion")[:2]) KODIVERSION = int(xbmc.getInfoLabel("System.BuildVersion")[:2])
KODILONGVERSION = xbmc.getInfoLabel('System.BuildVersion') KODILONGVERSION = xbmc.getInfoLabel('System.BuildVersion')
KODI_PROFILE = xbmc.translatePath("special://profile") KODI_PROFILE = tryDecode(xbmc.translatePath("special://profile"))
if xbmc.getCondVisibility('system.platform.osx'): if xbmc.getCondVisibility('system.platform.osx'):
PLATFORM = "MacOSX" PLATFORM = "MacOSX"
@ -70,8 +71,8 @@ _DB_VIDEO_VERSION = {
17: 107, # Krypton 17: 107, # Krypton
18: 108 # Leia 18: 108 # Leia
} }
DB_VIDEO_PATH = xbmc.translatePath( DB_VIDEO_PATH = tryDecode(xbmc.translatePath(
"special://database/MyVideos%s.db" % _DB_VIDEO_VERSION[KODIVERSION]) "special://database/MyVideos%s.db" % _DB_VIDEO_VERSION[KODIVERSION]))
_DB_MUSIC_VERSION = { _DB_MUSIC_VERSION = {
13: 46, # Gotham 13: 46, # Gotham
@ -81,8 +82,8 @@ _DB_MUSIC_VERSION = {
17: 60, # Krypton 17: 60, # Krypton
18: 62 # Leia 18: 62 # Leia
} }
DB_MUSIC_PATH = xbmc.translatePath( DB_MUSIC_PATH = tryDecode(xbmc.translatePath(
"special://database/MyMusic%s.db" % _DB_MUSIC_VERSION[KODIVERSION]) "special://database/MyMusic%s.db" % _DB_MUSIC_VERSION[KODIVERSION]))
_DB_TEXTURE_VERSION = { _DB_TEXTURE_VERSION = {
13: 13, # Gotham 13: 13, # Gotham
@ -92,13 +93,13 @@ _DB_TEXTURE_VERSION = {
17: 13, # Krypton 17: 13, # Krypton
18: 13 # Leia 18: 13 # Leia
} }
DB_TEXTURE_PATH = xbmc.translatePath( DB_TEXTURE_PATH = tryDecode(xbmc.translatePath(
"special://database/Textures%s.db" % _DB_TEXTURE_VERSION[KODIVERSION]) "special://database/Textures%s.db" % _DB_TEXTURE_VERSION[KODIVERSION]))
DB_PLEX_PATH = xbmc.translatePath("special://database/plex.db") DB_PLEX_PATH = tryDecode(xbmc.translatePath("special://database/plex.db"))
EXTERNAL_SUBTITLE_TEMP_PATH = xbmc.translatePath( EXTERNAL_SUBTITLE_TEMP_PATH = tryDecode(xbmc.translatePath(
"special://profile/addon_data/%s/temp/" % ADDON_ID) "special://profile/addon_data/%s/temp/" % ADDON_ID))
# Multiply Plex time by this factor to receive Kodi time # Multiply Plex time by this factor to receive Kodi time

View file

@ -3,14 +3,13 @@
import logging import logging
from shutil import copytree from shutil import copytree
import xml.etree.ElementTree as etree import xml.etree.ElementTree as etree
from os import remove, listdir, makedirs from os import makedirs
from os.path import isfile, join
import xbmc import xbmc
from xbmcvfs import exists from xbmcvfs import exists
from utils import window, settings, language as lang, tryEncode, indent, \ from utils import window, settings, language as lang, tryEncode, indent, \
normalize_nodes, exists_dir normalize_nodes, exists_dir, tryDecode
import variables as v import variables as v
############################################################################### ###############################################################################
@ -63,9 +62,10 @@ class VideoNodes(object):
dirname = viewid dirname = viewid
# Returns strings # Returns strings
path = xbmc.translatePath("special://profile/library/video/") path = tryDecode(xbmc.translatePath(
nodepath = xbmc.translatePath( "special://profile/library/video/"))
"special://profile/library/video/Plex-%s/" % dirname) nodepath = tryDecode(xbmc.translatePath(
"special://profile/library/video/Plex-%s/" % dirname))
if delete: if delete:
if exists_dir(nodepath): if exists_dir(nodepath):
@ -77,8 +77,10 @@ class VideoNodes(object):
# Verify the video directory # Verify the video directory
if not exists_dir(path): if not exists_dir(path):
copytree( copytree(
src=xbmc.translatePath("special://xbmc/system/library/video"), src=tryDecode(xbmc.translatePath(
dst=xbmc.translatePath("special://profile/library/video")) "special://xbmc/system/library/video")),
dst=tryDecode(xbmc.translatePath(
"special://profile/library/video")))
# Create the node directory # Create the node directory
if mediatype != "photos": if mediatype != "photos":
@ -290,7 +292,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 exists(nodeXML): if exists(tryEncode(nodeXML)):
# Don't recreate xml if already exists # Don't recreate xml if already exists
continue continue
@ -377,8 +379,9 @@ class VideoNodes(object):
def singleNode(self, indexnumber, tagname, mediatype, itemtype): def singleNode(self, indexnumber, tagname, mediatype, itemtype):
tagname = tryEncode(tagname) tagname = tryEncode(tagname)
cleantagname = normalize_nodes(tagname) cleantagname = tryDecode(normalize_nodes(tagname))
nodepath = xbmc.translatePath("special://profile/library/video/") nodepath = tryDecode(xbmc.translatePath(
"special://profile/library/video/"))
nodeXML = "%splex_%s.xml" % (nodepath, cleantagname) nodeXML = "%splex_%s.xml" % (nodepath, cleantagname)
path = "library://video/plex_%s.xml" % cleantagname path = "library://video/plex_%s.xml" % cleantagname
if v.KODIVERSION >= 17: if v.KODIVERSION >= 17:
@ -391,8 +394,10 @@ class VideoNodes(object):
if not exists_dir(nodepath): if not exists_dir(nodepath):
# We need to copy over the default items # We need to copy over the default items
copytree( copytree(
src=xbmc.translatePath("special://xbmc/system/library/video"), src=tryDecode(xbmc.translatePath(
dst=xbmc.translatePath("special://profile/library/video")) "special://xbmc/system/library/video")),
dst=tryDecode(xbmc.translatePath(
"special://profile/library/video")))
labels = { labels = {
'Favorite movies': 30180, 'Favorite movies': 30180,
@ -406,7 +411,7 @@ class VideoNodes(object):
window('%s.content' % embynode, value=path) window('%s.content' % embynode, value=path)
window('%s.type' % embynode, value=itemtype) window('%s.type' % embynode, value=itemtype)
if exists(nodeXML): if exists(tryEncode(nodeXML)):
# Don't recreate xml if already exists # Don't recreate xml if already exists
return return

View file

@ -30,7 +30,8 @@ sys_path.append(_base_resource)
############################################################################### ###############################################################################
from utils import settings, window, language as lang, dialog, tryEncode from utils import settings, window, language as lang, dialog, tryEncode, \
tryDecode
from userclient import UserClient from userclient import UserClient
import initialsetup import initialsetup
from kodimonitor import KodiMonitor from kodimonitor import KodiMonitor
@ -86,7 +87,7 @@ class Service():
window('plex_logLevel', value=str(logLevel)) window('plex_logLevel', value=str(logLevel))
window('plex_kodiProfile', window('plex_kodiProfile',
value=translatePath("special://profile")) value=tryDecode(translatePath("special://profile")))
window('plex_context', window('plex_context',
value='true' if settings('enableContext') == "true" else "") value='true' if settings('enableContext') == "true" else "")
window('fetch_pms_item_number', window('fetch_pms_item_number',
@ -170,12 +171,12 @@ class Service():
counter = 0 counter = 0
while not __stop_PKC(): while not __stop_PKC():
if tryEncode(window('plex_kodiProfile')) != kodiProfile: if window('plex_kodiProfile') != kodiProfile:
# Profile change happened, terminate this thread and others # Profile change happened, terminate this thread and others
log.warn("Kodi profile was: %s and changed to: %s. " log.warn("Kodi profile was: %s and changed to: %s. "
"Terminating old PlexKodiConnect thread." "Terminating old PlexKodiConnect thread."
% (kodiProfile, % (kodiProfile,
tryEncode(window('plex_kodiProfile')))) window('plex_kodiProfile')))
break break
# Before proceeding, need to make sure: # Before proceeding, need to make sure: