diff --git a/contextmenu.py b/contextmenu.py index bc640ef0..a7837684 100644 --- a/contextmenu.py +++ b/contextmenu.py @@ -10,13 +10,14 @@ import xbmc import xbmcaddon import xbmcgui +import utils + addon_ = xbmcaddon.Addon(id='plugin.video.plexkodiconnect') -addon_path = addon_.getAddonInfo('path').decode('utf-8') -base_resource = xbmc.translatePath(os.path.join(addon_path, 'resources', 'lib')).decode('utf-8') +addon_path = utils.tryDecode(addon_.getAddonInfo('path')) +base_resource = utils.tryDecode(xbmc.translatePath(os.path.join(addon_path, 'resources', 'lib'))) sys.path.append(base_resource) import artwork -import utils import clientinfo import downloadutils import librarysync @@ -36,8 +37,8 @@ def logMsg(msg, lvl=1): #Kodi contextmenu item to configure the emby settings #for now used to set ratings but can later be used to sync individual items etc. if __name__ == '__main__': - itemid = xbmc.getInfoLabel("ListItem.DBID").decode("utf-8") - itemtype = xbmc.getInfoLabel("ListItem.DBTYPE").decode("utf-8") + itemid = utils.tryDecode(xbmc.getInfoLabel("ListItem.DBID")) + itemtype = utils.tryDecode(xbmc.getInfoLabel("ListItem.DBTYPE")) emby = embyserver.Read_EmbyServer() diff --git a/default.py b/default.py index 948d82eb..65949e78 100644 --- a/default.py +++ b/default.py @@ -10,17 +10,18 @@ import xbmc import xbmcaddon import xbmcgui +import utils + ############################################################################### addon_ = xbmcaddon.Addon(id='plugin.video.plexkodiconnect') -addon_path = addon_.getAddonInfo('path').decode('utf-8') -base_resource = xbmc.translatePath(os.path.join(addon_path, 'resources', 'lib')).decode('utf-8') +addon_path = utils.tryDecode(addon_.getAddonInfo('path')) +base_resource = utils.tryDecode(xbmc.translatePath(os.path.join(addon_path, 'resources', 'lib'))) sys.path.append(base_resource) ############################################################################### import entrypoint -import utils ############################################################################### @@ -159,8 +160,8 @@ if ( __name__ == "__main__" ): import pstats import random from time import gmtime, strftime - addonid = addon_.getAddonInfo('id').decode( 'utf-8' ) - datapath = os.path.join( xbmc.translatePath( "special://profile/" ).decode( 'utf-8' ), "addon_data", addonid ) + addonid = utils.tryDecode(addon_.getAddonInfo('id')) + datapath = os.path.join(utils.tryDecode(xbmc.translatePath( "special://profile/" )), "addon_data", addonid ) filename = os.path.join( datapath, strftime( "%Y%m%d%H%M%S",gmtime() ) + "-" + str( random.randrange(0,100000) ) + ".log" ) cProfile.run( 'Main()', filename ) diff --git a/resources/lib/PlexAPI.py b/resources/lib/PlexAPI.py index c5fc9bf3..0b982ea5 100644 --- a/resources/lib/PlexAPI.py +++ b/resources/lib/PlexAPI.py @@ -482,8 +482,8 @@ class PlexAPI(): elif "Resource-Identifier:" in each: update['uuid'] = each.split(':')[1].strip() elif "Name:" in each: - update['serverName'] = each.split( - ':')[1].strip().decode('utf-8', 'replace') + update['serverName'] = utils.tryDecode(each.split( + ':')[1].strip()) elif "Port:" in each: update['port'] = each.split(':')[1].strip() elif "Updated-At:" in each: @@ -807,7 +807,7 @@ class PlexAPI(): username = user['title'] userlist.append(username) # To take care of non-ASCII usernames - userlistCoded.append(username.encode('utf-8')) + userlistCoded.append(utils.tryEncode(username)) usernumber = len(userlist) username = '' @@ -1039,7 +1039,7 @@ class PlexAPI(): path = 'http://127.0.0.1:32400' + key else: # internal path, add-on path = 'http://127.0.0.1:32400' + path + '/' + key - path = path.encode('utf8') + path = utils.tryEncode(path) # This is bogus (note the extra path component) but ATV is stupid when it comes to caching images, it doesn't use querystrings. # Fortunately PMS is lenient... @@ -1235,7 +1235,7 @@ class API(): res = None if res is not None: try: - res = unquote(res).decode('utf-8') + res = utils.tryDecode(unquote(res)) except UnicodeDecodeError: # Sometimes, Plex seems to have encoded in latin1 res = unquote(res).decode('latin1') @@ -1899,13 +1899,9 @@ class API(): url = 'http://api.themoviedb.org/3/search/%s' % media_type parameters = { 'api_key': apiKey, - 'language': KODILANGUAGE + 'language': KODILANGUAGE, + 'query': utils.tryEncode(title) } - try: - parameters['query'] = title.encode('utf-8', errors='ignore') - except TypeError: - # E.g. Android TV's python does NOT take arguments to encode - parameters['query'] = title.encode() data = downloadutils.DownloadUtils().downloadUrl( url, authenticate=False, @@ -2348,19 +2344,14 @@ class API(): # exist() needs a / or \ at the end to work for directories if folder is False: # files - check = True if xbmcvfs.exists(path.encode('utf-8')) == 1 \ - else False + check = xbmcvfs.exists(utils.tryEncode(path)) == 1 else: # directories if "\\" in path: # Add the missing backslash - check = True if \ - xbmcvfs.exists((path + "\\").encode('utf-8')) == 1 \ - else False + check = xbmcvfs.exists(utils.tryEncode(path + "\\")) == 1 else: - check = True if \ - xbmcvfs.exists((path + "/").encode('utf-8')) == 1 \ - else False + check = xbmcvfs.exists(utils.tryEncode(path + "/")) == 1 if check is False: if forceCheck is False: diff --git a/resources/lib/artwork.py b/resources/lib/artwork.py index 5b9fb8a5..ca0967fb 100644 --- a/resources/lib/artwork.py +++ b/resources/lib/artwork.py @@ -53,10 +53,10 @@ class Artwork(): def single_urlencode(self, text): - text = urllib.urlencode({'blahblahblah':text.encode("utf-8")}) #urlencode needs a utf- string + text = urllib.urlencode({'blahblahblah': utils.tryEncode(text)}) #urlencode needs a utf- string text = text[13:] - return text.decode("utf-8") #return the result again as unicode + return utils.tryDecode(text) #return the result again as unicode def setKodiWebServerDetails(self): # Get the Kodi webserver details - used to set the texture cache @@ -167,7 +167,7 @@ class Artwork(): string = xbmcaddon.Addon().getLocalizedString if not xbmcgui.Dialog().yesno( - "Image Texture Cache", string(39250).encode('utf-8')): + "Image Texture Cache", string(39250)): return self.logMsg("Doing Image Cache Sync", 1) @@ -177,19 +177,23 @@ class Artwork(): # ask to rest all existing or not if xbmcgui.Dialog().yesno( - "Image Texture Cache", string(39251).encode('utf-8'), ""): + "Image Texture Cache", string(39251), ""): self.logMsg("Resetting all cache data first", 1) # Remove all existing textures first - path = xbmc.translatePath("special://thumbnails/").decode('utf-8') + path = utils.tryDecode(xbmc.translatePath("special://thumbnails/")) if utils.IfExists(path): allDirs, allFiles = xbmcvfs.listdir(path) for dir in allDirs: allDirs, allFiles = xbmcvfs.listdir(path+dir) for file in allFiles: if os.path.supports_unicode_filenames: - xbmcvfs.delete(os.path.join(path+dir.decode('utf-8'),file.decode('utf-8'))) + xbmcvfs.delete(os.path.join( + path + utils.tryDecode(dir), + utils.tryDecode(file))) else: - xbmcvfs.delete(os.path.join(path.encode('utf-8')+dir,file)) + xbmcvfs.delete(os.path.join( + utils.tryEncode(path) + dir, + file)) # remove all existing data from texture DB textureconnection = utils.kodiSQL('texture') @@ -467,7 +471,8 @@ class Artwork(): self.logMsg("Database is locked. Skip deletion process.", 1) else: # Delete thumbnail as well as the entry - thumbnails = xbmc.translatePath("special://thumbnails/%s" % cachedurl).decode('utf-8') + thumbnails = utils.tryDecode( + xbmc.translatePath("special://thumbnails/%s" % cachedurl)) self.logMsg("Deleting cached thumbnail: %s" % thumbnails, 1) xbmcvfs.delete(thumbnails) diff --git a/resources/lib/clientinfo.py b/resources/lib/clientinfo.py index 2197ba82..e5ab7add 100644 --- a/resources/lib/clientinfo.py +++ b/resources/lib/clientinfo.py @@ -7,7 +7,7 @@ from uuid import uuid4 import xbmc import xbmcaddon -from utils import logging, window, settings +from utils import logging, window, settings, tryDecode ############################################################################### @@ -67,8 +67,7 @@ class ClientInfo(): def getDeviceName(self): if settings('deviceNameOpt') == "false": # Use Kodi's deviceName - deviceName = xbmc.getInfoLabel( - 'System.FriendlyName').decode('utf-8') + deviceName = tryDecode(xbmc.getInfoLabel('System.FriendlyName')) else: deviceName = settings('deviceName') deviceName = deviceName.replace("\"", "_") diff --git a/resources/lib/entrypoint.py b/resources/lib/entrypoint.py index 921750d9..e1ad3659 100644 --- a/resources/lib/entrypoint.py +++ b/resources/lib/entrypoint.py @@ -606,15 +606,15 @@ def getThemeMedia(): else: return - library = xbmc.translatePath( - "special://profile/addon_data/plugin.video.plexkodiconnect/library/").decode('utf-8') + library = utils.tryDecode(xbmc.translatePath( + "special://profile/addon_data/plugin.video.plexkodiconnect/library/")) # Create library directory if not utils.IfExists(library): xbmcvfs.mkdir(library) # Set custom path for user - tvtunes_path = xbmc.translatePath( - "special://profile/addon_data/script.tvtunes/").decode('utf-8') + tvtunes_path = utils.tryDecode(xbmc.translatePath( + "special://profile/addon_data/script.tvtunes/")) if xbmcvfs.exists(tvtunes_path): tvtunes = xbmcaddon.Addon(id="script.tvtunes") tvtunes.setSetting('custom_path_enable', "true") @@ -644,7 +644,8 @@ def getThemeMedia(): for item in result['Items']: itemId = item['Id'] folderName = item['Name'] - folderName = utils.normalize_string(folderName.encode('utf-8')) + folderName = utils.normalize_string( + utils.tryEncode(folderName)) itemIds[itemId] = folderName # Get paths for theme videos @@ -670,8 +671,8 @@ def getThemeMedia(): playurl = putils.directPlay() else: playurl = putils.directStream() - pathstowrite += ('%s' % playurl.encode('utf-8')) - + pathstowrite += ('%s' % utils.tryEncode(playurl)) + # Check if the item has theme songs and add them url = "{server}/emby/Items/%s/ThemeSongs?format=json" % itemId result = doUtils.downloadUrl(url) @@ -683,7 +684,7 @@ def getThemeMedia(): playurl = putils.directPlay() else: playurl = putils.directStream() - pathstowrite += ('%s' % playurl.encode('utf-8')) + pathstowrite += ('%s' % utils.tryEncode(playurl)) nfo_file.write( '%s' % pathstowrite @@ -700,7 +701,8 @@ def getThemeMedia(): for item in result['Items']: itemId = item['Id'] folderName = item['Name'] - folderName = utils.normalize_string(folderName.encode('utf-8')) + folderName = utils.normalize_string( + utils.tryEncode(folderName)) musicitemIds[itemId] = folderName # Get paths @@ -731,7 +733,7 @@ def getThemeMedia(): playurl = putils.directPlay() else: playurl = putils.directStream() - pathstowrite += ('%s' % playurl.encode('utf-8')) + pathstowrite += ('%s' % utils.tryEncode(playurl)) nfo_file.write( '%s' % pathstowrite @@ -781,12 +783,16 @@ def BrowseContent(viewname, browse_type="", folderid=""): if not folderid: views = PlexFunctions.GetPlexCollections() for view in views: - if view.get("name") == viewname.decode('utf-8'): + if view.get("name") == utils.tryDecode(viewname): folderid = view.get("id") break if viewname is not None: - utils.logMsg("BrowseContent","viewname: %s - type: %s - folderid: %s - filter: %s" %(viewname.decode('utf-8'), browse_type.decode('utf-8'), folderid.decode('utf-8'), filter_type.decode('utf-8'))) + utils.logMsg("BrowseContent", "viewname: %s - type: %s - folderid: %s " + "- filter: %s" % (utils.tryDecode(viewname), + utils.tryDecode(browse_type), + utils.tryDecode(folderid), + utils.tryDecode(filter_type))) #set the correct params for the content type #only proceed if we have a folderid if folderid: @@ -821,7 +827,11 @@ def BrowseContent(viewname, browse_type="", folderid=""): li = createListItemFromEmbyItem(item,art,doUtils) if item.get("IsFolder") == True: #for folders we add an additional browse request, passing the folderId - path = "%s?id=%s&mode=browsecontent&type=%s&folderid=%s" % (sys.argv[0].decode('utf-8'), viewname.decode('utf-8'), browse_type.decode('utf-8'), item.get("Id").decode('utf-8')) + path = "%s?id=%s&mode=browsecontent&type=%s&folderid=%s" \ + % (utils.tryDecode(sys.argv[0]), + utils.tryDecode(viewname), + utils.tryDecode(browse_type), + utils.tryDecode(item.get("Id"))) xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=path, listitem=li, isFolder=True) else: #playable item, set plugin path and mediastreams @@ -1330,16 +1340,16 @@ def getVideoFiles(plexId, params): # Careful, returns encoded strings! dirs, files = xbmcvfs.listdir(path) for file in files: - file = path + file.decode('utf-8') + file = path + utils.tryDecode(file) li = xbmcgui.ListItem(file, path=file) xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), - url=file.encode('utf-8'), + url=utils.tryEncode(file), listitem=li) for dir in dirs: - dir = path + dir.decode('utf-8') + dir = path + utils.tryDecode(dir) li = xbmcgui.ListItem(dir, path=dir) xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), - url=dir.encode('utf-8'), + url=utils.tryEncode(dir), listitem=li, isFolder=True) else: @@ -1367,7 +1377,8 @@ def getExtraFanArt(embyId,embyPath): # We need to store the images locally for this to work # because of the caching system in xbmc - fanartDir = xbmc.translatePath("special://thumbnails/emby/%s/" % embyId).decode('utf-8') + fanartDir = utils.tryDecode(xbmc.translatePath( + "special://thumbnails/emby/%s/" % embyId)) if not xbmcvfs.exists(fanartDir): # Download the images to the cache directory @@ -1383,7 +1394,9 @@ def getExtraFanArt(embyId,embyPath): if os.path.supports_unicode_filenames: fanartFile = os.path.join(fanartDir, "fanart%s.jpg" % tag) else: - fanartFile = os.path.join(fanartDir.encode("utf-8"), "fanart%s.jpg" % tag.encode("utf-8")) + fanartFile = os.path.join( + utils.tryEncode(fanartDir), + "fanart%s.jpg" % utils.tryEncode(tag)) li = xbmcgui.ListItem(tag, path=fanartFile) xbmcplugin.addDirectoryItem( handle=int(sys.argv[1]), @@ -1396,7 +1409,7 @@ def getExtraFanArt(embyId,embyPath): # Use existing cached images dirs, files = xbmcvfs.listdir(fanartDir) for file in files: - fanartFile = os.path.join(fanartDir, file.decode('utf-8')) + fanartFile = os.path.join(fanartDir, utils.tryDecode(file)) li = xbmcgui.ListItem(file, path=fanartFile) xbmcplugin.addDirectoryItem( handle=int(sys.argv[1]), @@ -1458,7 +1471,11 @@ def BrowsePlexContent(viewid, mediatype="", nodetype=""): # folderId li.setProperty('IsFolder', 'true') li.setProperty('IsPlayable', 'false') - 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')) + path = "%s?id=%s&mode=browsecontent&type=%s&folderid=%s" \ + % (utils.tryDecode(sys.argv[0]), + utils.tryDecode(viewname), + utils.tryDecode(type), + utils.tryDecode(item.get("Id"))) xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=path, listitem=li, isFolder=True) else: # playable item, set plugin path and mediastreams diff --git a/resources/lib/itemtypes.py b/resources/lib/itemtypes.py index 1b28f910..249ac908 100644 --- a/resources/lib/itemtypes.py +++ b/resources/lib/itemtypes.py @@ -432,7 +432,7 @@ class Movies(Items): # Set plugin path and media flags using real filename path = "plugin://plugin.video.plexkodiconnect.movies/" params = { - 'filename': API.getKey().encode('utf-8'), + 'filename': utils.tryEncode(API.getKey()), 'id': itemid, 'dbid': movieid, 'mode': "play" @@ -691,7 +691,7 @@ class MusicVideos(Items): path = "plugin://plugin.video.plexkodiconnect.musicvideos/" params = { - 'filename': filename.encode('utf-8'), + 'filename': utils.tryEncode(filename), 'id': itemid, 'dbid': mvideoid, 'mode': "play" @@ -1332,7 +1332,7 @@ class TVShows(Items): filename = 'file_not_found' path = "plugin://plugin.video.plexkodiconnect.tvshows/%s/" % seriesId params = { - 'filename': filename.encode('utf-8'), + 'filename': utils.tryEncode(filename), 'id': itemid, 'dbid': episodeid, 'mode': "play" diff --git a/resources/lib/kodimonitor.py b/resources/lib/kodimonitor.py index 3ea4953c..59262908 100644 --- a/resources/lib/kodimonitor.py +++ b/resources/lib/kodimonitor.py @@ -173,7 +173,7 @@ class KodiMonitor(xbmc.Monitor): return else: count += 1 - log("Currently playing file is: %s" % currentFile.decode('utf-8'), 1) + log("Currently playing file is: %s" % utils.tryDecode(currentFile), 1) # Try to get a Kodi ID item = data.get('item') @@ -217,7 +217,7 @@ class KodiMonitor(xbmc.Monitor): return # Save currentFile for cleanup later and to be able to access refs - window('plex_lastPlayedFiled', value=currentFile.decode('utf-8')) + window('plex_lastPlayedFiled', value=utils.tryDecode(currentFile)) window('Plex_currently_playing_itemid', value=plexid) window("emby_%s.itemid" % currentFile, value=plexid) log('Finish playback startup', 1) diff --git a/resources/lib/librarysync.py b/resources/lib/librarysync.py index 54e7f378..68eba341 100644 --- a/resources/lib/librarysync.py +++ b/resources/lib/librarysync.py @@ -1619,8 +1619,8 @@ class LibrarySync(Thread): # Database does not exists log("The current Kodi version is incompatible " "to know which Kodi versions are supported.", -1) - log('Current Kodi version: %s' % xbmc.getInfoLabel( - 'System.BuildVersion').decode('utf-8')) + log('Current Kodi version: %s' % utils.tryDecode( + xbmc.getInfoLabel('System.BuildVersion'))) # "Current Kodi version is unsupported, cancel lib sync" self.dialog.ok(heading=self.addonName, line1=string(39403)) diff --git a/resources/lib/musicutils.py b/resources/lib/musicutils.py index 3a7dc294..c594b926 100644 --- a/resources/lib/musicutils.py +++ b/resources/lib/musicutils.py @@ -32,7 +32,7 @@ def getRealFileName(filename, isTemp=False): if os.path.supports_unicode_filenames: checkfile = filename else: - checkfile = filename.encode("utf-8") + checkfile = utils.tryEncode(filename) # determine if our python module is able to access the file directly... if os.path.exists(checkfile): @@ -46,7 +46,7 @@ def getRealFileName(filename, isTemp=False): else: filepart = filename.split("\\")[-1] tempfile = "special://temp/"+filepart xbmcvfs.copy(filename, tempfile) - filename = xbmc.translatePath(tempfile).decode("utf-8") + filename = utils.tryDecode(xbmc.translatePath(tempfile)) return (isTemp,filename) @@ -242,7 +242,7 @@ def updateRatingToFile(rating, file): else: filepart = file.split("\\")[-1] tempfile = "special://temp/"+filepart xbmcvfs.copy(file, tempfile) - tempfile = xbmc.translatePath(tempfile).decode("utf-8") + tempfile = utils.tryDecode(xbmc.translatePath(tempfile)) logMsg( "setting song rating: %s for filename: %s - using tempfile: %s" %(rating,file,tempfile)) diff --git a/resources/lib/playbackutils.py b/resources/lib/playbackutils.py index a29acc2d..b060805e 100644 --- a/resources/lib/playbackutils.py +++ b/resources/lib/playbackutils.py @@ -75,14 +75,14 @@ class PlaybackUtils(): % item[0][0][0].attrib.get('key'), -1) return xbmcplugin.setResolvedUrl( int(sys.argv[1]), False, listitem) - playurl = xml[0].attrib.get('key').encode('utf-8') + playurl = utils.tryEncode(xml[0].attrib.get('key')) window('emby_%s.playmethod' % playurl, value='DirectStream') playmethod = window('emby_%s.playmethod' % playurl) if playmethod == "Transcode": window('emby_%s.playmethod' % playurl, clear=True) - playurl = playutils.audioSubsPref( - listitem, playurl.decode('utf-8')).encode('utf-8') + playurl = utils.tryEncode(playutils.audioSubsPref( + listitem, utils.tryDecode(playurl))) window('emby_%s.playmethod' % playurl, "Transcode") listitem.setPath(playurl) self.setProperties(playurl, listitem) @@ -195,8 +195,8 @@ class PlaybackUtils(): # For transcoding only, ask for audio/subs pref if window('emby_%s.playmethod' % playurl) == "Transcode": window('emby_%s.playmethod' % playurl, clear=True) - playurl = playutils.audioSubsPref( - listitem, playurl.decode('utf-8')).encode('utf-8') + playurl = utils.tryEncode(playutils.audioSubsPref( + listitem, utils.tryDecode(playurl))) window('emby_%s.playmethod' % playurl, value="Transcode") listitem.setPath(playurl) diff --git a/resources/lib/player.py b/resources/lib/player.py index ec2f788f..70dc67a4 100644 --- a/resources/lib/player.py +++ b/resources/lib/player.py @@ -72,7 +72,7 @@ class Player(xbmc.Player): # Save currentFile for cleanup later and for references self.currentFile = currentFile - window('plex_lastPlayedFiled', value=currentFile.decode('utf-8')) + window('plex_lastPlayedFiled', value=utils.tryDecode(currentFile)) # We may need to wait for info to be set in kodi monitor itemId = window("emby_%s.itemid" % currentFile) count = 0 @@ -87,7 +87,7 @@ class Player(xbmc.Player): count += 1 self.logMsg("ONPLAYBACK_STARTED: %s itemid: %s" - % (currentFile.decode('utf-8'), itemId), 0) + % (utils.tryDecode(currentFile), itemId), 0) embyitem = "emby_%s" % currentFile runtime = window("%s.runtime" % embyitem) @@ -399,7 +399,7 @@ class Player(xbmc.Player): def onPlayBackPaused(self): currentFile = self.currentFile - self.logMsg("PLAYBACK_PAUSED: %s" % currentFile.decode('utf-8'), 2) + self.logMsg("PLAYBACK_PAUSED: %s" % utils.tryDecode(currentFile), 2) if self.played_info.get(currentFile): self.played_info[currentFile]['paused'] = True @@ -409,7 +409,7 @@ class Player(xbmc.Player): def onPlayBackResumed(self): currentFile = self.currentFile - self.logMsg("PLAYBACK_RESUMED: %s" % currentFile.decode('utf-8'), 2) + self.logMsg("PLAYBACK_RESUMED: %s" % utils.tryDecode(currentFile), 2) if self.played_info.get(currentFile): self.played_info[currentFile]['paused'] = False @@ -419,7 +419,7 @@ class Player(xbmc.Player): def onPlayBackSeek(self, time, seekOffset): # Make position when seeking a bit more accurate currentFile = self.currentFile - self.logMsg("PLAYBACK_SEEK: %s" % currentFile.decode('utf-8'), 2) + self.logMsg("PLAYBACK_SEEK: %s" % utils.tryDecode(currentFile), 2) if self.played_info.get(currentFile): position = self.xbmcplayer.getTime() diff --git a/resources/lib/playutils.py b/resources/lib/playutils.py index 20b84a8e..1eff107a 100644 --- a/resources/lib/playutils.py +++ b/resources/lib/playutils.py @@ -45,13 +45,14 @@ class PlayUtils(): if playurl: log("File is direct playing.", 1) - playurl = playurl.encode('utf-8') + playurl = utils.tryEncode(playurl) # Set playmethod property window('emby_%s.playmethod' % playurl, "DirectPlay") elif self.isDirectStream(): self.logMsg("File is direct streaming.", 1) - playurl = self.API.getTranscodeVideoPath('DirectStream').encode('utf-8') + playurl = utils.tryEncode( + self.API.getTranscodeVideoPath('DirectStream')) # Set playmethod property utils.window('emby_%s.playmethod' % playurl, "DirectStream") @@ -62,9 +63,9 @@ class PlayUtils(): 'videoResolution': self.getResolution(), 'videoQuality': '100' } - playurl = self.API.getTranscodeVideoPath( + playurl = utils.tryEncode(self.API.getTranscodeVideoPath( 'Transcode', - quality=quality).encode('utf-8') + quality=quality)) # Set playmethod property window('emby_%s.playmethod' % playurl, value="Transcode") @@ -306,7 +307,7 @@ class PlayUtils(): #audioStreamsChannelsList[audioNum] = stream.attrib['channels'] audioStreamsList.append(index) - audioStreams.append(track.encode('utf-8')) + audioStreams.append(utils.tryEncode(track)) audioNum += 1 # Subtitles @@ -330,7 +331,7 @@ class PlayUtils(): downloadableStreams.append(index) subtitleStreamsList.append(index) - subtitleStreams.append(track.encode('utf-8')) + subtitleStreams.append(utils.tryEncode(track)) subNum += 1 if audioNum > 1: @@ -362,7 +363,7 @@ class PlayUtils(): % (self.server, selectSubsIndex) url = self.API.addPlexHeadersToUrl(url) self.logMsg("Downloadable sub: %s: %s" % (selectSubsIndex, url), 1) - listitem.setSubtitles([url.encode('utf-8')]) + listitem.setSubtitles([utils.tryEncode(url)]) else: self.logMsg('Need to burn in subtitle %s' % selectSubsIndex, 1) playurlprefs["subtitleStreamID"] = selectSubsIndex diff --git a/resources/lib/userclient.py b/resources/lib/userclient.py index bca74bdd..6f515cd3 100644 --- a/resources/lib/userclient.py +++ b/resources/lib/userclient.py @@ -247,8 +247,8 @@ class UserClient(threading.Thread): return False # Get /profile/addon_data - addondir = xbmc.translatePath( - self.addon.getAddonInfo('profile')).decode('utf-8') + addondir = utils.tryDecode(xbmc.translatePath( + self.addon.getAddonInfo('profile'))) hasSettings = xbmcvfs.exists("%ssettings.xml" % addondir) # If there's no settings.xml diff --git a/resources/lib/utils.py b/resources/lib/utils.py index cb93e3b2..21e8f4a0 100644 --- a/resources/lib/utils.py +++ b/resources/lib/utils.py @@ -98,7 +98,7 @@ def IfExists(path): Returns True if path exists, else false """ - dummyfile = os.path.join(path, 'dummyfile.txt').encode('utf-8') + dummyfile = tryEncode(os.path.join(path, 'dummyfile.txt')) try: etree.ElementTree(etree.Element('test')).write(dummyfile) except: @@ -272,7 +272,7 @@ def logMsg(title, msg, level=1): except UnicodeEncodeError: try: xbmc.log("%s -> %s : %s" % ( - title, func.co_name, msg.encode('utf-8')), + title, func.co_name, tryEncode(msg)), level=kodiLevel[level]) except: xbmc.log("%s -> %s : %s" % ( @@ -283,7 +283,7 @@ def logMsg(title, msg, level=1): xbmc.log("%s -> %s" % (title, msg), level=kodiLevel[level]) except UnicodeEncodeError: try: - xbmc.log("%s -> %s" % (title, msg.encode('utf-8')), + xbmc.log("%s -> %s" % (title, tryEncode(msg)), level=kodiLevel[level]) except: xbmc.log("%s -> %s " % (title, 'COULDNT LOG'), @@ -301,16 +301,12 @@ def window(property, value=None, clear=False, windowid=10000): 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 - '''if isinstance(property, unicode): - property = property.encode("utf-8") - if isinstance(value, unicode): - value = value.encode("utf-8")''' if clear: WINDOW.clearProperty(property) elif value is not None: - WINDOW.setProperty(property, value.encode('utf-8')) + WINDOW.setProperty(property, tryEncode(value)) else: - return WINDOW.getProperty(property).decode('utf-8') + return tryDecode(WINDOW.getProperty(property)) def settings(setting, value=None): """ @@ -323,10 +319,10 @@ def settings(setting, value=None): if value is not None: # Takes string or unicode by default! - addon.setSetting(setting, value.encode('utf-8')) + addon.setSetting(setting, tryEncode(value)) else: # Should return unicode by default, but just in case - return addon.getSetting(setting).decode('utf-8') + return tryDecode(addon.getSetting(setting)) def language(stringid): # Central string retrieval @@ -337,11 +333,12 @@ def language(stringid): def kodiSQL(media_type="video"): if media_type == "emby": - dbPath = xbmc.translatePath("special://database/emby.db").decode('utf-8') + dbPath = tryDecode(xbmc.translatePath("special://database/emby.db")) elif media_type == "music": dbPath = getKodiMusicDBPath() elif media_type == "texture": - dbPath = xbmc.translatePath("special://database/Textures13.db").decode('utf-8') + dbPath = tryDecode(xbmc.translatePath( + "special://database/Textures13.db")) else: dbPath = getKodiVideoDBPath() @@ -359,9 +356,9 @@ def getKodiVideoDBPath(): "17": 104 # Krypton } - dbPath = xbmc.translatePath( - "special://database/MyVideos%s.db" - % dbVersion.get(xbmc.getInfoLabel('System.BuildVersion')[:2], "")).decode('utf-8') + dbPath = tryDecode(xbmc.translatePath( + "special://database/MyVideos%s.db" + % dbVersion.get(xbmc.getInfoLabel('System.BuildVersion')[:2], ""))) return dbPath def getKodiMusicDBPath(): @@ -375,9 +372,9 @@ def getKodiMusicDBPath(): "17": 60 # Krypton } - dbPath = xbmc.translatePath( - "special://database/MyMusic%s.db" - % dbVersion.get(xbmc.getInfoLabel('System.BuildVersion')[:2], "")).decode('utf-8') + dbPath = tryDecode(xbmc.translatePath( + "special://database/MyMusic%s.db" + % dbVersion.get(xbmc.getInfoLabel('System.BuildVersion')[:2], ""))) return dbPath def getScreensaver(): @@ -479,16 +476,20 @@ def reset(): if resp: logMsg("EMBY", "Resetting all cached artwork.", 0) # Remove all existing textures first - path = xbmc.translatePath("special://thumbnails/").decode('utf-8') + path = tryDecode(xbmc.translatePath("special://thumbnails/")) if xbmcvfs.exists(path): allDirs, allFiles = xbmcvfs.listdir(path) for dir in allDirs: allDirs, allFiles = xbmcvfs.listdir(path+dir) for file in allFiles: if os.path.supports_unicode_filenames: - xbmcvfs.delete(os.path.join(path+dir.decode('utf-8'),file.decode('utf-8'))) + xbmcvfs.delete(os.path.join( + path + tryDecode(dir), + tryDecode(file))) else: - xbmcvfs.delete(os.path.join(path.encode('utf-8')+dir,file)) + xbmcvfs.delete(os.path.join( + tryEncode(path) + dir, + file)) # remove all existing data from texture DB connection = kodiSQL('texture') @@ -510,9 +511,9 @@ def reset(): if resp: # Delete the settings addon = xbmcaddon.Addon() - addondir = xbmc.translatePath(addon.getAddonInfo('profile')).decode('utf-8') + addondir = tryDecode(xbmc.translatePath(addon.getAddonInfo('profile'))) dataPath = "%ssettings.xml" % addondir - xbmcvfs.delete(dataPath.encode('utf-8')) + xbmcvfs.delete(tryEncode(dataPath)) logMsg("PLEX", "Deleting: settings.xml", 1) dialog.ok( @@ -567,7 +568,7 @@ def normalize_nodes(text): # Remove dots from the last character as windows can not have directories # with dots at the end text = text.rstrip('.') - text = unicodedata.normalize('NFKD', unicode(text, 'utf-8')).encode('ascii', 'ignore') + text = tryEncode(unicodedata.normalize('NFKD', unicode(text, 'utf-8'))) return text @@ -586,7 +587,7 @@ def normalize_string(text): # Remove dots from the last character as windows can not have directories # with dots at the end text = text.rstrip('.') - text = unicodedata.normalize('NFKD', unicode(text, 'utf-8')).encode('ascii', 'ignore') + text = tryEncode(unicodedata.normalize('NFKD', unicode(text, 'utf-8'))) return text @@ -611,7 +612,7 @@ def guisettingsXML(): """ Returns special://userdata/guisettings.xml as an etree xml root element """ - path = xbmc.translatePath("special://profile/").decode('utf-8') + path = tryDecode(xbmc.translatePath("special://profile/")) xmlpath = "%sguisettings.xml" % path try: @@ -670,7 +671,7 @@ def advancedSettingsXML(): usetags : set to "false" findremotethumbs : set to "false" """ - path = xbmc.translatePath("special://profile/").decode('utf-8') + path = tryDecode(xbmc.translatePath("special://profile/")) xmlpath = "%sadvancedsettings.xml" % path try: @@ -700,7 +701,7 @@ def advancedSettingsXML(): def sourcesXML(): # To make Master lock compatible - path = xbmc.translatePath("special://profile/").decode('utf-8') + path = tryDecode(xbmc.translatePath("special://profile/")) xmlpath = "%ssources.xml" % path try: @@ -741,7 +742,7 @@ def sourcesXML(): def passwordsXML(): # To add network credentials - path = xbmc.translatePath("special://userdata/").decode('utf-8') + path = tryDecode(xbmc.translatePath("special://userdata/")) xmlpath = "%spasswords.xml" % path logMsg('passwordsXML', 'Path to passwords.xml: %s' % xmlpath, 1) @@ -852,7 +853,7 @@ def playlistXSP(mediatype, tagname, viewid, viewtype="", delete=False): """ Feed with tagname as unicode """ - path = xbmc.translatePath("special://profile/playlists/video/").decode('utf-8') + path = tryDecode(xbmc.translatePath("special://profile/playlists/video/")) if viewtype == "mixed": plname = "%s - %s" % (tagname, mediatype) xsppath = "%sPlex %s - %s.xsp" % (path, viewid, mediatype) @@ -861,15 +862,15 @@ def playlistXSP(mediatype, tagname, viewid, viewtype="", delete=False): xsppath = "%sPlex %s.xsp" % (path, viewid) # Create the playlist directory - if not xbmcvfs.exists(path.encode('utf-8')): + if not xbmcvfs.exists(tryEncode(path)): logMsg("PLEX", "Creating directory: %s" % path, 1) - xbmcvfs.mkdirs(path.encode('utf-8')) + xbmcvfs.mkdirs(tryEncode(path)) # Only add the playlist if it doesn't already exists - if xbmcvfs.exists(xsppath.encode('utf-8')): + if xbmcvfs.exists(tryEncode(xsppath)): logMsg('Path %s does exist' % xsppath, 1) if delete: - xbmcvfs.delete(xsppath.encode('utf-8')) + xbmcvfs.delete(tryEncode(xsppath)) logMsg("PLEX", "Successfully removed playlist: %s." % tagname, 1) return @@ -882,12 +883,12 @@ def playlistXSP(mediatype, tagname, viewid, viewtype="", delete=False): } logMsg("Plex", "Writing playlist file to: %s" % xsppath, 1) try: - f = xbmcvfs.File(xsppath.encode('utf-8'), 'wb') + f = xbmcvfs.File(tryEncode(xsppath), 'wb') except: logMsg("Plex", "Failed to create playlist: %s" % xsppath, -1) return else: - f.write(( + f.write(tryEncode( '\n' '\n\t' 'Plex %s\n\t' @@ -896,35 +897,61 @@ def playlistXSP(mediatype, tagname, viewid, viewtype="", delete=False): '%s\n\t' '\n' '\n' - % (itemtypes.get(mediatype, mediatype), plname, tagname)) - .encode('utf-8')) + % (itemtypes.get(mediatype, mediatype), plname, tagname))) f.close() logMsg("Plex", "Successfully added playlist: %s" % tagname) def deletePlaylists(): # Clean up the playlists - path = xbmc.translatePath("special://profile/playlists/video/").decode('utf-8') - dirs, files = xbmcvfs.listdir(path.encode('utf-8')) + path = tryDecode(xbmc.translatePath("special://profile/playlists/video/")) + dirs, files = xbmcvfs.listdir(tryEncode(path)) for file in files: - if file.decode('utf-8').startswith('Plex'): - xbmcvfs.delete(("%s%s" % (path, file.decode('utf-8'))).encode('utf-8')) + if tryDecode(file).startswith('Plex'): + xbmcvfs.delete(tryEncode("%s%s" % (path, tryDecode(file)))) def deleteNodes(): # Clean up video nodes import shutil - path = xbmc.translatePath("special://profile/library/video/").decode('utf-8') - dirs, files = xbmcvfs.listdir(path.encode('utf-8')) + path = tryDecode(xbmc.translatePath("special://profile/library/video/")) + dirs, files = xbmcvfs.listdir(tryEncode(path)) for dir in dirs: - if dir.decode('utf-8').startswith('Plex'): + if tryDecode(dir).startswith('Plex'): try: - shutil.rmtree("%s%s" % (path, dir.decode('utf-8'))) + shutil.rmtree("%s%s" % (path, tryDecode(dir))) except: - logMsg("PLEX", "Failed to delete directory: %s" % dir.decode('utf-8')) + logMsg("PLEX", "Failed to delete directory: %s" + % tryDecode(dir)) for file in files: - if file.decode('utf-8').startswith('plex'): + if tryDecode(file).startswith('plex'): try: - xbmcvfs.delete(("%s%s" % (path, file.decode('utf-8'))).encode('utf-8')) + xbmcvfs.delete(tryEncode("%s%s" % (path, tryDecode(file)))) except: - logMsg("PLEX", "Failed to file: %s" % file.decode('utf-8')) + logMsg("PLEX", "Failed to file: %s" % tryDecode(file)) + + +def tryEncode(uniString, encoding='utf-8'): + """ + Will try to encode uniString (in unicode) to encoding. This possibly + fails with e.g. Android TV's Python, which does not accept arguments for + string.encode() + """ + try: + uniString.encode(encoding, "ignore") + except TypeError: + uniString.encode() + return uniString + + +def tryDecode(string, encoding='utf-8'): + """ + Will try to decode string (encoded) using encoding. This possibly + fails with e.g. Android TV's Python, which does not accept arguments for + string.encode() + """ + try: + string.decode(encoding, "ignore") + except TypeError: + string.decode() + return string diff --git a/resources/lib/videonodes.py b/resources/lib/videonodes.py index fce5c169..24ef7be2 100644 --- a/resources/lib/videonodes.py +++ b/resources/lib/videonodes.py @@ -60,9 +60,10 @@ class VideoNodes(object): else: dirname = viewid - path = xbmc.translatePath("special://profile/library/video/").decode('utf-8') - nodepath = xbmc.translatePath( - "special://profile/library/video/Plex-%s/" % dirname).decode('utf-8') + path = utils.tryDecode(xbmc.translatePath( + "special://profile/library/video/")) + nodepath = utils.tryDecode(xbmc.translatePath( + "special://profile/library/video/Plex-%s/" % dirname)) # Verify the video directory # KODI BUG @@ -70,20 +71,22 @@ class VideoNodes(object): # so try creating a file if utils.IfExists(path) is False: shutil.copytree( - src=xbmc.translatePath("special://xbmc/system/library/video").decode('utf-8'), - dst=xbmc.translatePath("special://profile/library/video").decode('utf-8')) + src=utils.tryDecode(xbmc.translatePath( + "special://xbmc/system/library/video")), + dst=utils.tryDecode(xbmc.translatePath( + "special://profile/library/video"))) # Create the node directory if mediatype != "photo": if utils.IfExists(nodepath) is False: # folder does not exist yet self.logMsg('Creating folder %s' % nodepath, 1) - xbmcvfs.mkdirs(nodepath.encode('utf-8')) + xbmcvfs.mkdirs(utils.tryEncode(nodepath)) if delete: - dirs, files = xbmcvfs.listdir(nodepath.encode('utf-8')) + dirs, files = xbmcvfs.listdir(utils.tryEncode(nodepath)) for file in files: - xbmcvfs.delete( - (nodepath + file.decode('utf-8')).encode('utf-8')) + xbmcvfs.delete(utils.tryEncode( + (nodepath + utils.tryDecode(file)))) self.logMsg("Sucessfully removed videonode: %s." % tagname, 1) @@ -273,7 +276,7 @@ class VideoNodes(object): # To do: add our photos nodes to kodi picture sources somehow continue - if xbmcvfs.exists(nodeXML.encode('utf-8')): + if xbmcvfs.exists(utils.tryEncode(nodeXML)): # Don't recreate xml if already exists continue @@ -357,19 +360,22 @@ class VideoNodes(object): window = utils.window - tagname = tagname.encode('utf-8') + tagname = utils.tryEncode(tagname) cleantagname = utils.normalize_nodes(tagname) - nodepath = xbmc.translatePath("special://profile/library/video/").decode('utf-8') + nodepath = utils.tryDecode(xbmc.translatePath( + "special://profile/library/video/")) nodeXML = "%splex_%s.xml" % (nodepath, cleantagname) path = "library://video/plex_%s.xml" % cleantagname windowpath = "ActivateWindow(Video,%s,return)" % path - + # Create the video node directory if not xbmcvfs.exists(nodepath): # We need to copy over the default items shutil.copytree( - src=xbmc.translatePath("special://xbmc/system/library/video").decode('utf-8'), - dst=xbmc.translatePath("special://profile/library/video").decode('utf-8')) + src=utils.tryDecode(xbmc.translatePath( + "special://xbmc/system/library/video")), + dst=utils.tryDecode(xbmc.translatePath( + "special://profile/library/video"))) xbmcvfs.exists(path) labels = { diff --git a/resources/lib/websocket.py b/resources/lib/websocket.py index e35d1966..326a60db 100644 --- a/resources/lib/websocket.py +++ b/resources/lib/websocket.py @@ -46,6 +46,8 @@ import logging import traceback import sys +import utils + """ websocket python client. ========================= @@ -286,7 +288,7 @@ class ABNF(object): opcode: operation code. please see OPCODE_XXX. """ if opcode == ABNF.OPCODE_TEXT and isinstance(data, unicode): - data = data.encode("utf-8") + data = utils.tryEncode(data) # mask must be set if send data from client return ABNF(1, 0, 0, 0, opcode, 1, data) diff --git a/service.py b/service.py index 6de8cd67..74ee7f98 100644 --- a/service.py +++ b/service.py @@ -11,11 +11,15 @@ import xbmc import xbmcaddon import xbmcgui +import utils ############################################################################### _addon = xbmcaddon.Addon(id='plugin.video.plexkodiconnect') -addon_path = _addon.getAddonInfo('path').decode('utf-8') -base_resource = xbmc.translatePath(os.path.join(addon_path, 'resources', 'lib')).decode('utf-8') +addon_path = utils.tryDecode(_addon.getAddonInfo('path')) +base_resource = utils.tryDecode(xbmc.translatePath(os.path.join( + addon_path, + 'resources', + 'lib'))) sys.path.append(base_resource) ############################################################################### @@ -26,7 +30,6 @@ import initialsetup import kodimonitor import librarysync import player -import utils import videonodes import websocket_client as wsc import downloadutils