diff --git a/README.md b/README.md index e398413f..1c14e0e8 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ [![stable version](https://img.shields.io/badge/stable_version-1.7.7-blue.svg?maxAge=60&style=flat) ](https://dl.bintray.com/croneter/PlexKodiConnect/bin/repository.plexkodiconnect/repository.plexkodiconnect-1.0.0.zip) -[![beta version](https://img.shields.io/badge/beta_version-1.7.12-red.svg?maxAge=60&style=flat) ](https://dl.bintray.com/croneter/PlexKodiConnect_BETA/bin-BETA/repository.plexkodiconnectbeta/repository.plexkodiconnectbeta-1.0.0.zip) +[![beta version](https://img.shields.io/badge/beta_version-1.7.17-red.svg?maxAge=60&style=flat) ](https://dl.bintray.com/croneter/PlexKodiConnect_BETA/bin-BETA/repository.plexkodiconnectbeta/repository.plexkodiconnectbeta-1.0.0.zip) [![Installation](https://img.shields.io/badge/wiki-installation-brightgreen.svg?maxAge=60&style=flat)](https://github.com/croneter/PlexKodiConnect/wiki/Installation) [![FAQ](https://img.shields.io/badge/wiki-FAQ-brightgreen.svg?maxAge=60&style=flat)](https://github.com/croneter/PlexKodiConnect/wiki/faq) diff --git a/addon.xml b/addon.xml index 2476c915..c8b7d5eb 100644 --- a/addon.xml +++ b/addon.xml @@ -1,5 +1,5 @@ - + @@ -44,7 +44,32 @@ Gebruik op eigen risico 使用風險由您自己承擔 Usar a su propio riesgo - version 1.7.12 (beta only) + version 1.7.17 (beta only) +- Don't add media by other add-ons to queue +- Fix KeyError for Plex Companion +- Repace Kodi mkdirs with os.makedirs +- Use xbmcvfs exists instead of os.path.exists + +version 1.7.16 (beta only) +- Fix PKC complaining about files not found +- Fix multiple subtitles per language not showing +- Update Czech translation +- Fix too many arguments when marking 100% watched +- More small fixes + +version 1.7.15 (beta only) +- Fix companion for "Playback via PMS" +- Change sleeping behavior for playqueue client +- Plex Companion: add itemType to playstate +- Less logging + +version 1.7.14 (beta only) +- Fix TypeError, but for real now + +version 1.7.13 (beta only) +- Fix TypeError with AdvancedSettings.xml missing + +version 1.7.12 (beta only) - Major music overhaul: Direct Paths should now work! Many thanks @Memesa for the pointers! Don't forget to reset your database - Some Plex Companion fixes - Fix UnicodeDecodeError on user switch diff --git a/changelog.txt b/changelog.txt index 03a188c2..866eb44d 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,28 @@ +version 1.7.17 (beta only) +- Don't add media by other add-ons to queue +- Fix KeyError for Plex Companion +- Repace Kodi mkdirs with os.makedirs +- Use xbmcvfs exists instead of os.path.exists + +version 1.7.16 (beta only) +- Fix PKC complaining about files not found +- Fix multiple subtitles per language not showing +- Update Czech translation +- Fix too many arguments when marking 100% watched +- More small fixes + +version 1.7.15 (beta only) +- Fix companion for "Playback via PMS" +- Change sleeping behavior for playqueue client +- Plex Companion: add itemType to playstate +- Less logging + +version 1.7.14 (beta only) +- Fix TypeError, but for real now + +version 1.7.13 (beta only) +- Fix TypeError with AdvancedSettings.xml missing + version 1.7.12 (beta only) - Major music overhaul: Direct Paths should now work! Many thanks @Memesa for the pointers! Don't forget to reset your database - Some Plex Companion fixes diff --git a/resources/language/resource.language.en_gb/strings.po b/resources/language/resource.language.en_gb/strings.po index f88e31b5..e43dbf53 100644 --- a/resources/language/resource.language.en_gb/strings.po +++ b/resources/language/resource.language.en_gb/strings.po @@ -1899,3 +1899,23 @@ msgstr "" msgctxt "#39711" msgid "New Plex music library detected. Sorry, but we need to restart Kodi now due to the changes made." msgstr "" + +# Shown during sync process +msgctxt "#39712" +msgid "downloaded" +msgstr "" + +# Shown during sync process +msgctxt "#39713" +msgid "processed" +msgstr "" + +# Shown during sync process +msgctxt "#39714" +msgid "Sync" +msgstr "" + +# Shown during sync process +msgctxt "#39715" +msgid "items" +msgstr "" diff --git a/resources/lib/PKC_listitem.py b/resources/lib/PKC_listitem.py index 4d9081a7..e34a0019 100644 --- a/resources/lib/PKC_listitem.py +++ b/resources/lib/PKC_listitem.py @@ -1,21 +1,13 @@ # -*- coding: utf-8 -*- ############################################################################### -import logging - from xbmcgui import ListItem -############################################################################### -log = logging.getLogger("PLEX."+__name__) - -############################################################################### - def convert_PKC_to_listitem(PKC_listitem): """ Insert a PKC_listitem and you will receive a valid XBMC listitem """ data = PKC_listitem.data - log.debug('data is: %s' % data) listitem = ListItem(label=data.get('label'), label2=data.get('label2'), path=data.get('path')) diff --git a/resources/lib/PlexAPI.py b/resources/lib/PlexAPI.py index 1c53396d..fbd28e7c 100644 --- a/resources/lib/PlexAPI.py +++ b/resources/lib/PlexAPI.py @@ -39,16 +39,17 @@ import xml.etree.ElementTree as etree from re import compile as re_compile, sub from json import dumps from urllib import urlencode, quote_plus, unquote -from os.path import basename, join, exists +from os.path import basename, join from os import makedirs import xbmcgui from xbmc import sleep, executebuiltin +from xbmcvfs import exists import clientinfo as client from downloadutils import DownloadUtils from utils import window, settings, language as lang, tryDecode, tryEncode, \ - DateToKodi + DateToKodi, exists_dir from PlexFunctions import PMSHttpsEnabled import plexdb_functions as plexdb import variables as v @@ -2117,10 +2118,9 @@ class API(): continue if fanartcount > maxfanarts: break - if exists(tryEncode(entry['url'])): - allartworks['Backdrop'].append( - entry['url'].replace(' ', '%20')) - fanartcount += 1 + allartworks['Backdrop'].append( + entry['url'].replace(' ', '%20')) + fanartcount += 1 return allartworks def getSetArtwork(self, parentInfo=False): @@ -2303,6 +2303,7 @@ class API(): except (TypeError, KeyError, IndexError): return kodiindex = 0 + fileindex = 0 for stream in mediastreams: # Since plex returns all possible tracks together, have to pull # only external subtitles - only for these a 'key' exists @@ -2318,8 +2319,10 @@ class API(): if stream.attrib.get('languageCode') is not None: path = self.download_external_subtitles( "{server}%s" % key, - "subtitle.%s.%s" % (stream.attrib['languageCode'], - stream.attrib['codec'])) + "subtitle%02d.%s.%s" % (fileindex, + stream.attrib['languageCode'], + stream.attrib['codec'])) + fileindex += 1 # We don't know the language - no need to download else: path = self.addPlexCredentialsToUrl( @@ -2341,7 +2344,7 @@ class API(): Returns the path to the downloaded subtitle or None """ - if not exists(v.EXTERNAL_SUBTITLE_TEMP_PATH): + if not exists_dir(v.EXTERNAL_SUBTITLE_TEMP_PATH): makedirs(v.EXTERNAL_SUBTITLE_TEMP_PATH) path = join(v.EXTERNAL_SUBTITLE_TEMP_PATH, filename) r = DownloadUtils().downloadUrl(url, return_response=True) @@ -2541,16 +2544,22 @@ class API(): # exist() needs a / or \ at the end to work for directories if folder is False: # files - check = exists(tryEncode(path)) == 1 + check = exists(tryEncode(path)) else: # directories if "\\" in path: - # Add the missing backslash - check = exists(tryEncode(path + "\\")) == 1 + if not path.endswith('\\'): + # Add the missing backslash + check = exists_dir(tryEncode(path + "\\")) + else: + check = exists_dir(tryEncode(path)) else: - check = exists(tryEncode(path + "/")) == 1 + if not path.endswith('/'): + check = exists_dir(tryEncode(path + "/")) + else: + check = exists_dir(tryEncode(path)) - if check is False: + if not check: if forceCheck is False: # Validate the path is correct with user intervention if self.askToValidate(path): diff --git a/resources/lib/artwork.py b/resources/lib/artwork.py index be076403..4efc05d4 100644 --- a/resources/lib/artwork.py +++ b/resources/lib/artwork.py @@ -4,16 +4,16 @@ import logging from json import dumps, loads import requests -from os.path import exists from shutil import rmtree from urllib import quote_plus, unquote from threading import Thread from Queue import Queue, Empty from xbmc import executeJSONRPC, sleep, translatePath +from xbmcvfs import exists from utils import window, settings, language as lang, kodiSQL, tryEncode, \ - ThreadMethods, ThreadMethodsAdditionalStop, dialog + ThreadMethods, ThreadMethodsAdditionalStop, dialog, exists_dir # Disable annoying requests warnings import requests.packages.urllib3 @@ -229,7 +229,7 @@ class Artwork(): log.info("Resetting all cache data first") # Remove all existing textures first path = translatePath("special://thumbnails/") - if exists(path): + if exists_dir(path): rmtree(path, ignore_errors=True) # remove all existing data from texture DB diff --git a/resources/lib/entrypoint.py b/resources/lib/entrypoint.py index dea40bfe..8ab911cd 100644 --- a/resources/lib/entrypoint.py +++ b/resources/lib/entrypoint.py @@ -3,7 +3,7 @@ import logging from shutil import copyfile from os import walk, makedirs -from os.path import basename, join, exists +from os.path import basename, join from sys import argv from urllib import urlencode @@ -12,7 +12,7 @@ from xbmc import sleep, executebuiltin, translatePath from xbmcgui import ListItem from utils import window, settings, language as lang, dialog, tryEncode, \ - CatchExceptions, JSONRPC + CatchExceptions, JSONRPC, exists_dir import downloadutils from PlexFunctions import GetPlexMetadata, GetPlexSectionResults, \ @@ -74,7 +74,7 @@ def togglePlexTV(): if settings('plexToken'): log.info('Reseting plex.tv credentials in settings') settings('plexLogin', value="") - settings('plexToken', value=""), + settings('plexToken', value="") settings('plexid', value="") settings('plexHomeSize', value="1") settings('plexAvatar', value="") @@ -498,7 +498,7 @@ def getVideoFiles(plexId, params): path = path.replace('\\', '\\\\') # Directory only, get rid of filename path = path.replace(basename(path), '') - if exists(path): + if exists_dir(path): for root, dirs, files in walk(path): for directory in dirs: item_path = join(root, directory) @@ -513,6 +513,7 @@ def getVideoFiles(plexId, params): xbmcplugin.addDirectoryItem(handle=HANDLE, url=file, listitem=li) + break else: log.error('Kodi cannot access folder %s' % path) xbmcplugin.endOfDirectory(HANDLE) @@ -536,7 +537,7 @@ def getExtraFanArt(plexid, plexPath): # We need to store the images locally for this to work # because of the caching system in xbmc fanartDir = translatePath("special://thumbnails/plex/%s/" % plexid) - if not exists(fanartDir): + if not exists_dir(fanartDir): # Download the images to the cache directory makedirs(fanartDir) xml = GetPlexMetadata(plexid) diff --git a/resources/lib/initialsetup.py b/resources/lib/initialsetup.py index 887c04a0..54bd9940 100644 --- a/resources/lib/initialsetup.py +++ b/resources/lib/initialsetup.py @@ -402,11 +402,11 @@ class InitialSetup(): # Get current Kodi video cache setting cache, _ = advancedsettings_xml(['cache', 'memorysize']) - if cache is not None: - cache = str(cache.text) - else: + if cache is None: # Kodi default cache cache = '20971520' + else: + cache = str(cache.text) log.info('Current Kodi video memory cache in bytes: %s' % cache) settings('kodi_video_cache', value=cache) diff --git a/resources/lib/itemtypes.py b/resources/lib/itemtypes.py index b7175530..f0bac9a3 100644 --- a/resources/lib/itemtypes.py +++ b/resources/lib/itemtypes.py @@ -165,7 +165,7 @@ class Items(object): 'Mark item played at %s percent.' % (item['ratingKey'], str(complete), MARK_PLAYED_AT), 1) if complete >= MARK_PLAYED_AT: - log.info('Marking as completely watched in Kodi', 1) + log.info('Marking as completely watched in Kodi') sleep(500) try: item['viewCount'] += 1 @@ -1189,10 +1189,9 @@ class TVShows(Items): v.KODI_TYPE_SEASON) for season in seasons: self.removeSeason(season[1]) - else: - # Delete plex season entries - plex_db.removeItems_byParentId(showid, - v.KODI_TYPE_SEASON) + # Delete plex season entries + plex_db.removeItems_byParentId(showid, + v.KODI_TYPE_SEASON) self.removeShow(showid) plex_db.removeItem(show[0]) @@ -1208,14 +1207,12 @@ class TVShows(Items): seasonid, v.KODI_TYPE_EPISODE) for episode in season_episodes: self.removeEpisode(episode[1], episode[2]) - else: - # Remove plex episodes - plex_db.removeItems_byParentId(seasonid, - v.KODI_TYPE_EPISODE) - else: - # Remove plex seasons - plex_db.removeItems_byParentId(kodiid, - v.KODI_TYPE_SEASON) + # Remove plex episodes + plex_db.removeItems_byParentId(seasonid, + v.KODI_TYPE_EPISODE) + # Remove plex seasons + plex_db.removeItems_byParentId(kodiid, + v.KODI_TYPE_SEASON) # Remove tvshow self.removeShow(kodiid) @@ -1228,9 +1225,8 @@ class TVShows(Items): v.KODI_TYPE_EPISODE) for episode in season_episodes: self.removeEpisode(episode[1], episode[2]) - else: - # Remove plex episodes - plex_db.removeItems_byParentId(kodiid, v.KODI_TYPE_EPISODE) + # Remove plex episodes + plex_db.removeItems_byParentId(kodiid, v.KODI_TYPE_EPISODE) # Remove season self.removeSeason(kodiid) diff --git a/resources/lib/kodidb_functions.py b/resources/lib/kodidb_functions.py index 2dd5ad90..9e595aab 100644 --- a/resources/lib/kodidb_functions.py +++ b/resources/lib/kodidb_functions.py @@ -1409,9 +1409,8 @@ class Kodidb_Functions(): ID = 'idEpisode' elif kodi_type == v.KODI_TYPE_SONG: ID = 'idSong' - query = ('''UPDATE %s SET userrating = ? WHERE %s = ?''' - % (kodi_type, ID)) - self.cursor.execute(query, (userrating, kodi_id)) + query = '''UPDATE ? SET userrating = ? WHERE ? = ?''' + self.cursor.execute(query, (kodi_type, userrating, ID, kodi_id)) def create_entry_uniqueid(self): self.cursor.execute( diff --git a/resources/lib/library_sync/sync_info.py b/resources/lib/library_sync/sync_info.py index df14e433..3be8f70b 100644 --- a/resources/lib/library_sync/sync_info.py +++ b/resources/lib/library_sync/sync_info.py @@ -54,9 +54,8 @@ class Threaded_Show_Sync_Info(Thread): total = self.total dialog = self.dialog threadStopped = self.threadStopped - dialog.create("%s: Sync %s: %s items" - % (lang(29999), self.item_type, str(total)), - "Starting") + dialog.create("%s %s: %s %s" + % (lang(39714), self.item_type, str(total), lang(39715))) total = 2 * total totalProgress = 0 @@ -71,9 +70,11 @@ class Threaded_Show_Sync_Info(Thread): except ZeroDivisionError: percentage = 0 dialog.update(percentage, - message="%s downloaded. %s processed: %s" + message="%s %s. %s %s: %s" % (get_progress, + lang(39712), process_progress, + lang(39713), viewName)) # Sleep for x milliseconds sleep(200) diff --git a/resources/lib/librarysync.py b/resources/lib/librarysync.py index 75c4217b..60e1a0e9 100644 --- a/resources/lib/librarysync.py +++ b/resources/lib/librarysync.py @@ -4,10 +4,10 @@ import logging from threading import Thread import Queue from random import shuffle -from os.path import exists import xbmc import xbmcgui +from xbmcvfs import exists from utils import window, settings, getUnixTimestamp, sourcesXML,\ ThreadMethods, ThreadMethodsAdditionalStop, LogTime, getScreensaver,\ @@ -297,15 +297,6 @@ class LibrarySync(Thread): } if self.enableMusic: process['music'] = self.PlexMusic - if self.direct_paths is True: - if music.set_excludefromscan_music_folders() is True: - log.info('Detected new Music library - restarting now') - # 'New Plex music library detected. Sorry, but we need to - # restart Kodi now due to the changes made.' - dialog('ok', lang(29999), lang(39711)) - from xbmc import executebuiltin - executebuiltin('RestartApp') - return False # Do the processing for itemtype in process: @@ -483,6 +474,16 @@ class LibrarySync(Thread): """ Compare the views to Plex """ + if self.direct_paths is True: + if music.set_excludefromscan_music_folders() is True: + log.info('Detected new Music library - restarting now') + # 'New Plex music library detected. Sorry, but we need to + # restart Kodi now due to the changes made.' + dialog('ok', lang(29999), lang(39711)) + from xbmc import executebuiltin + executebuiltin('RestartApp') + return False + self.views = [] vnodes = self.vnodes diff --git a/resources/lib/playbackutils.py b/resources/lib/playbackutils.py index 56a45695..00fb5551 100644 --- a/resources/lib/playbackutils.py +++ b/resources/lib/playbackutils.py @@ -200,7 +200,7 @@ class PlaybackUtils(): playqueue, self.currentPosition+1, convert_PKC_to_listitem(listitem), - playurl, + file=playurl, kodi_item={'id': kodi_id, 'type': kodi_type}) else: # Full metadata$ diff --git a/resources/lib/playlist_func.py b/resources/lib/playlist_func.py index b3a9f143..fa439cde 100644 --- a/resources/lib/playlist_func.py +++ b/resources/lib/playlist_func.py @@ -75,6 +75,7 @@ class Playqueue_Object(Playlist_Object_Baseclase): class Playlist_Item(object): ID = None # Plex playlist/playqueue id, e.g. playQueueItemID plex_id = None # Plex unique item id, "ratingKey" + plex_type = None # Plex type, e.g. 'movie', 'clip' plex_UUID = None # Plex librarySectionUUID kodi_id = None # Kodi unique kodi id (unique only within type!) kodi_type = None # Kodi type: 'movie' @@ -102,20 +103,22 @@ def playlist_item_from_kodi(kodi_item): """ item = Playlist_Item() item.kodi_id = kodi_item.get('id') + item.kodi_type = kodi_item.get('type') if item.kodi_id: with plexdb.Get_Plex_DB() as plex_db: plex_dbitem = plex_db.getItem_byKodiId(kodi_item['id'], kodi_item['type']) try: item.plex_id = plex_dbitem[0] + item.plex_type = plex_dbitem[2] item.plex_UUID = plex_dbitem[0] # we dont need the uuid yet :-) except TypeError: pass item.file = kodi_item.get('file') - if item.file is not None and item.plex_id is None: - item.plex_id = dict( - parse_qsl(urlsplit(item.file).query)).get('plex_id') - item.kodi_type = kodi_item.get('type') + if item.plex_id is None and item.file is not None: + query = dict(parse_qsl(urlsplit(item.file).query)) + item.plex_id = query.get('plex_id') + item.plex_type = query.get('itemType') if item.plex_id is None: item.uri = 'library://whatever/item/%s' % quote(item.file, safe='') else: @@ -137,13 +140,14 @@ def playlist_item_from_plex(plex_id): with plexdb.Get_Plex_DB() as plex_db: plex_dbitem = plex_db.getItem_byId(plex_id) try: + item.plex_type = plex_dbitem[5] item.kodi_id = plex_dbitem[0] item.kodi_type = plex_dbitem[4] except: raise KeyError('Could not find plex_id %s in database' % plex_id) item.plex_UUID = plex_id item.uri = ('library://%s/item/library%%2Fmetadata%%2F%s' % - (item.plex_UUID, plex_id)) + (item.plex_UUID, plex_id)) log.debug('Made playlist item from plex: %s' % item) return item @@ -155,6 +159,7 @@ def playlist_item_from_xml(playlist, xml_video_element): item = Playlist_Item() api = API(xml_video_element) item.plex_id = api.getRatingKey() + item.plex_type = api.getType() item.ID = xml_video_element.attrib['%sItemID' % playlist.kind] item.guid = xml_video_element.attrib.get('guid') if item.guid is not None: @@ -314,8 +319,6 @@ def add_item_to_PMS_playlist(playlist, pos, plex_id=None, kodi_item=None): WILL ALSO UPDATE OUR PLAYLISTS """ - log.debug('Adding new item plex_id: %s, kodi_item: %s on the Plex side at ' - 'position %s for %s' % (plex_id, kodi_item, pos, playlist)) if plex_id: try: item = playlist_item_from_plex(plex_id) @@ -532,9 +535,10 @@ def add_listitem_to_Kodi_playlist(playlist, pos, listitem, file, # We need to add this to our internal queue as well if xml_video_element is not None: item = playlist_item_from_xml(playlist, xml_video_element) - item.file = file else: item = playlist_item_from_kodi(kodi_item) + if file is not None: + item.file = file playlist.items.insert(pos, item) log.debug('Done inserting for %s' % playlist) diff --git a/resources/lib/playqueue.py b/resources/lib/playqueue.py index 551bd5f3..a496574b 100644 --- a/resources/lib/playqueue.py +++ b/resources/lib/playqueue.py @@ -17,6 +17,7 @@ log = logging.getLogger("PLEX."+__name__) # Lock used for playqueue manipulations lock = RLock() +PLUGIN = 'plugin://%s' % v.ADDON_ID ############################################################################### @@ -147,11 +148,19 @@ class Playqueue(Thread): log.debug('Comparing new Kodi playqueue %s with our play queue %s' % (new, old)) for i, new_item in enumerate(new): + if (new_item['file'].startswith('plugin://') and + not new_item['file'].startswith(PLUGIN)): + # Ignore new media added by other addons + continue for j, old_item in enumerate(old): if self.threadStopped(): # Chances are that we got an empty Kodi playlist due to # Kodi exit return + if (old_item['file'].startswith('plugin://') and + not old_item['file'].startswith(PLUGIN)): + # Ignore media by other addons + continue if new_item.get('id') is None: identical = old_item.file == new_item['file'] else: @@ -206,5 +215,9 @@ class Playqueue(Thread): # compare old and new playqueue self._compare_playqueues(playqueue, kodi_playqueue) playqueue.old_kodi_pl = list(kodi_playqueue) - sleep(50) + # Still sleep a bit so Kodi does not become + # unresponsive + sleep(10) + continue + sleep(200) log.info("----===## PlayQueue client stopped ##===----") diff --git a/resources/lib/plexbmchelper/subscribers.py b/resources/lib/plexbmchelper/subscribers.py index 22d77f64..b8f4e20b 100644 --- a/resources/lib/plexbmchelper/subscribers.py +++ b/resources/lib/plexbmchelper/subscribers.py @@ -122,9 +122,11 @@ class SubscriptionManager: ret += ' shuffle="%s"' % info['shuffle'] ret += ' mute="%s"' % self.mute ret += ' repeat="%s"' % info['repeat'] + ret += ' itemType="%s"' % info['itemType'] # Might need an update in the future - ret += ' subtitleStreamID="-1"' - ret += ' audioStreamID="-1"' + if ptype == 'video': + ret += ' subtitleStreamID="-1"' + ret += ' audioStreamID="-1"' ret += '/>' return ret @@ -225,7 +227,8 @@ class SubscriptionManager: props = self.js.jsonrpc( "Player.GetProperties", {"playerid": playerid, - "properties": ["time", + "properties": ["type", + "time", "totaltime", "speed", "shuffled", @@ -244,12 +247,13 @@ class SubscriptionManager: {"playerid": playerid, "properties": ["position"]})['position'] try: - info['playQueueItemID'] = playqueue.items[pos].ID - info['guid'] = playqueue.items[pos].guid - info['playQueueID'] = playqueue.ID - info['playQueueVersion'] = playqueue.version + info['playQueueItemID'] = playqueue.items[pos].ID or 'null' + info['guid'] = playqueue.items[pos].guid or 'null' + info['playQueueID'] = playqueue.ID or 'null' + info['playQueueVersion'] = playqueue.version or 'null' + info['itemType'] = playqueue.items[pos].plex_type or 'null' except: - pass + info['itemType'] = props.get('type') or 'null' except: import traceback log.error("Traceback:\n%s" % traceback.format_exc()) diff --git a/resources/lib/plexdb_functions.py b/resources/lib/plexdb_functions.py index 179518dc..1fdbe07d 100644 --- a/resources/lib/plexdb_functions.py +++ b/resources/lib/plexdb_functions.py @@ -258,10 +258,11 @@ class Plex_DB_Functions(): def getItem_byKodiId(self, kodi_id, kodi_type): """ - Returns the tuple (plex_id, parent_id) for kodi_id and kodi_type + Returns the tuple (plex_id, parent_id, plex_type) for kodi_id and + kodi_type """ query = ''' - SELECT plex_id, parent_id + SELECT plex_id, parent_id, plex_type FROM plex WHERE kodi_id = ? AND kodi_type = ? diff --git a/resources/lib/userclient.py b/resources/lib/userclient.py index ebd790bd..04f97d16 100644 --- a/resources/lib/userclient.py +++ b/resources/lib/userclient.py @@ -3,11 +3,11 @@ ############################################################################### import logging import threading -from os.path import exists import xbmc import xbmcgui import xbmcaddon +from xbmcvfs import exists from utils import window, settings, language as lang, ThreadMethods, \ @@ -211,10 +211,9 @@ class UserClient(threading.Thread): # Get /profile/addon_data addondir = xbmc.translatePath(self.addon.getAddonInfo('profile')) - hasSettings = exists("%ssettings.xml" % addondir) # If there's no settings.xml - if not hasSettings: + if not exists("%ssettings.xml" % addondir): log.error("Error, no settings.xml found.") self.auth = False return False diff --git a/resources/lib/utils.py b/resources/lib/utils.py index 752801cf..e94f7555 100644 --- a/resources/lib/utils.py +++ b/resources/lib/utils.py @@ -13,17 +13,18 @@ from unicodedata import normalize import xml.etree.ElementTree as etree from functools import wraps from calendar import timegm -from os.path import exists, join -from os import remove, makedirs, walk +from os.path import join +from os import remove, walk, makedirs from shutil import rmtree from urllib import quote_plus import xbmc import xbmcaddon import xbmcgui +from xbmcvfs import exists, delete from variables import DB_VIDEO_PATH, DB_MUSIC_PATH, DB_TEXTURE_PATH, \ - DB_PLEX_PATH, KODI_PROFILE + DB_PLEX_PATH, KODI_PROFILE, KODIVERSION ############################################################################### @@ -91,6 +92,30 @@ def settings(setting, value=None): return tryDecode(addon.getSetting(setting)) +def exists_dir(path): + """ + Safe way to check whether the directory path exists already (broken in Kodi + <17) + + Feed with encoded string + """ + if KODIVERSION >= 17: + answ = exists(path) + else: + dummyfile = join(path, 'dummyfile.txt') + try: + with open(dummyfile, 'w') as f: + f.write('text') + except IOError: + # folder does not exist yet + answ = 0 + else: + # Folder exists. Delete file again. + delete(dummyfile) + answ = 1 + return answ + + def language(stringid): # Central string retrieval return ADDON.getLocalizedString(stringid) @@ -322,7 +347,7 @@ def reset(): for row in rows: tablename = row[0] if tablename != "version": - cursor.execute("DELETE FROM " + tablename) + cursor.execute("DELETE FROM ?", (tablename,)) connection.commit() cursor.close() @@ -335,7 +360,7 @@ def reset(): for row in rows: tablename = row[0] if tablename != "version": - cursor.execute("DELETE FROM " + tablename) + cursor.execute("DELETE FROM ?", (tablename, )) connection.commit() cursor.close() @@ -348,7 +373,7 @@ def reset(): for row in rows: tablename = row[0] if tablename != "version": - cursor.execute("DELETE FROM " + tablename) + cursor.execute("DELETE FROM ?", (tablename, )) cursor.execute('DROP table IF EXISTS plex') cursor.execute('DROP table IF EXISTS view') connection.commit() @@ -372,7 +397,7 @@ def reset(): for row in rows: tableName = row[0] if(tableName != "version"): - cursor.execute("DELETE FROM " + tableName) + cursor.execute("DELETE FROM ?", (tableName, )) connection.commit() cursor.close() @@ -542,8 +567,10 @@ def __setSubElement(element, subelement): def advancedsettings_xml(node_list, new_value=None, attrib=None, force_create=False): """ - Returns the etree element for nodelist (if it exists) and the tree. None if - not set + Returns + etree element, tree + or + None, None node_list is a list of node names starting from the outside, ignoring the outter advancedsettings. Example nodelist=['video', 'busydialogdelayms'] @@ -576,7 +603,7 @@ def advancedsettings_xml(node_list, new_value=None, attrib=None, # Document is blank or missing if new_value is None and attrib is None and force_create is False: log.debug('Could not parse advancedsettings.xml, returning None') - return + return None, None # Create topmost xml entry tree = etree.ElementTree(element=etree.Element('advancedsettings')) root = tree.getroot() diff --git a/resources/lib/videonodes.py b/resources/lib/videonodes.py index 4ffc91e7..f6561ad8 100644 --- a/resources/lib/videonodes.py +++ b/resources/lib/videonodes.py @@ -3,13 +3,14 @@ import logging from shutil import copytree import xml.etree.ElementTree as etree +from os import remove, listdir, makedirs +from os.path import isfile, join import xbmc -from os import remove, makedirs, listdir -from os.path import exists, isfile, join +from xbmcvfs import exists from utils import window, settings, language as lang, tryEncode, indent, \ - normalize_nodes + normalize_nodes, exists_dir import variables as v ############################################################################### @@ -74,14 +75,14 @@ class VideoNodes(object): return # Verify the video directory - if exists(path) is False: + if not exists_dir(path): copytree( src=xbmc.translatePath("special://xbmc/system/library/video"), dst=xbmc.translatePath("special://profile/library/video")) # Create the node directory if mediatype != "photos": - if exists(nodepath) is False: + if not exists_dir(nodepath): # folder does not exist yet log.debug('Creating folder %s' % nodepath) makedirs(nodepath) @@ -387,7 +388,7 @@ class VideoNodes(object): windowpath = "ActivateWindow(Video,%s,return)" % path # Create the video node directory - if not exists(nodepath): + if not exists_dir(nodepath): # We need to copy over the default items copytree( src=xbmc.translatePath("special://xbmc/system/library/video"),