From cfbc7f770c5fbb711604bd2c272210afcdcfa4c3 Mon Sep 17 00:00:00 2001 From: tomkat83 Date: Sat, 25 Jun 2016 16:02:40 +0200 Subject: [PATCH] Use playing item filename and path to find ID - Fixes #67 - Everything else doesn 't work --- resources/lib/kodidb_functions.py | 133 +++++++++++++++--------------- resources/lib/kodimonitor.py | 106 +++++++++++------------- resources/lib/utils.py | 3 + 3 files changed, 115 insertions(+), 127 deletions(-) diff --git a/resources/lib/kodidb_functions.py b/resources/lib/kodidb_functions.py index 95113ba6..9174df88 100644 --- a/resources/lib/kodidb_functions.py +++ b/resources/lib/kodidb_functions.py @@ -792,86 +792,83 @@ class Kodidb_Functions(): ids.append(row[0]) return ids - def getIdFromTitle(self, itemdetails): + def getIdFromFilename(self, filename, path): """ - Returns the Kodi id (e.g. idMovie, idEpisode) from the item's - title (c00), if there is exactly ONE found for the itemtype. - (None otherwise) + Returns the tuple (itemId, type) where + itemId: Kodi DB unique Id for either movie or episode + type: either 'movie' or 'episode' - itemdetails is the data['item'] response from Kodi - - itemdetails for movies: - { - "title":"Kung Fu Panda", - "type":"movie", - "year":2008 - } - - itemdetails for episodes: - { - "episode":5 - "season":5, - "showtitle":"Girls", - "title":"Queen for Two Days", - "type":"episode" - } + Returns None if not found OR if too many entries were found """ - try: - typus = itemdetails['type'] - except: + query = ' '.join(( + "SELECT idFile, idPath", + "FROM files", + "WHERE strFilename = ?" + )) + self.cursor.execute(query, (filename,)) + files = self.cursor.fetchall() + if len(files) == 0: + self.logMsg('Did not find any file, abort', 1) return - - if typus == 'movie': - query = ' '.join(( - "SELECT idMovie", - "FROM movie", - "WHERE c00 = ?" - )) + query = ' '.join(( + "SELECT strPath", + "FROM path", + "WHERE idPath = ?" + )) + # result will contain a list of all idFile with matching filename and + # matching path + result = [] + for file in files: + # Use idPath to get path as a string + self.cursor.execute(query, (file[1],)) try: - rows = self.cursor.execute(query, (itemdetails['title'],)) - except: - return - elif typus == 'episode': - query = ' '.join(( - "SELECT idShow", - "FROM tvshow", - "WHERE c00 = ?" - )) - try: - rows = self.cursor.execute(query, (itemdetails['showtitle'],)) - except: - return - ids = [] - for row in rows: - ids.append(row[0]) - if len(ids) > 1: - self.logMsg('No unique match possible. Rows: %s' % rows, 1) - return + strPath = self.cursor.fetchone()[0] + except TypeError: + # idPath not found; skip + continue + # For whatever reason, double might have become triple + strPath = strPath.replace('///', '//') + strPath = strPath.replace('\\\\\\', '\\\\') + if strPath == path: + result.append(file[0]) + if len(result) == 0: + self.logMsg('Did not find matching paths, abort', 1) + return + self.logMsg('Result: %s' % result) + # Kodi seems to make ONE temporary entry; we only want the earlier, + # permanent one + if len(result) > 2: + self.logMsg('We found too many items with matching filenames and ' + ' paths, aborting', 1) + return + idFile = result[0] + self.logMsg('idFile: %s' % idFile) + # Try movies first + query = ' '.join(( + "SELECT idMovie", + "FROM movie", + "WHERE idFile = ?" + )) + self.cursor.execute(query, (idFile,)) + try: + itemId = self.cursor.fetchone()[0] + typus = 'movie' + except TypeError: + # Try tv shows next query = ' '.join(( "SELECT idEpisode", "FROM episode", - "WHERE c12 = ? AND c13 = ? AND idShow = ?" + "WHERE idFile = ?" )) + self.cursor.execute(query, (idFile,)) try: - rows = self.cursor.execute( - query, - (itemdetails['season'], - itemdetails['episode'], - ids[0])) - except: + itemId = self.cursor.fetchone()[0] + typus = 'episode' + except TypeError: + self.logMsg('Unexpectantly did not find a match!', 1) return - else: - return - - ids = [] - for row in rows: - ids.append(row[0]) - if len(ids) == 1: - return ids[0] - else: - # No unique match possible - return + return itemId, typus def getUnplayedItems(self): """ diff --git a/resources/lib/kodimonitor.py b/resources/lib/kodimonitor.py index 971bfa92..3c6bf23a 100644 --- a/resources/lib/kodimonitor.py +++ b/resources/lib/kodimonitor.py @@ -177,7 +177,9 @@ class KodiMonitor(xbmc.Monitor): return else: count += 1 - log("Currently playing file is: %s" % utils.tryDecode(currentFile), 1) + # Just to be on the safe side + currentFile = utils.tryDecode(currentFile) + log("Currently playing file is: %s" % currentFile, 1) # Get the type of media we're playing try: @@ -185,81 +187,67 @@ class KodiMonitor(xbmc.Monitor): except (TypeError, KeyError): log("Item is invalid for PMS playstate update.", 0) return - log("Playing itemtype is: %s" % typus, 1) + log("Playing itemtype is (or appears to be): %s" % typus, 1) # Try to get a Kodi ID - try: - kodiid = data['item']['id'] - except (TypeError, KeyError): - log('Could not get Kodi id directly, trying jsonrpc', 1) + # If PKC was used - native paths, not direct paths + plexid = utils.window('emby_%s.itemid' + % utils.tryEncode(currentFile)) + # Get rid of the '' if the window property was not set + plexid = None if not plexid else plexid + kodiid = None + if plexid is None: + log('Did not get Plex id from window properties', 1) try: - playerid = data["player"]["playerid"] + kodiid = data['item']['id'] except (TypeError, KeyError): - log("Could not get Kodi playerid. Abort playback report", 0) - return - # Get details of the playing media - result = xbmc.executeJSONRPC(json.dumps({ - "jsonrpc": "2.0", - "id": 1, - "method": "Player.GetItem", - "params": { - "playerid": playerid, - # Just ask something so we get the item's id (for movies) - "properties": [ - "tvshowid", "title" - ] - } - })) - result = json.loads(result) - - kodiid = None - if typus in ('movie', 'song'): - key = 'id' - elif typus == 'episode': - key = 'tvshowid' - else: - log('Unknown type, abort playback report', 1) - return + log('Did not get a Kodi id from Kodi, darn', 1) + # For direct paths, if we're not streaming something + # When using Widgets, Kodi doesn't tell us shit so we need this hack + if (kodiid is None and plexid is None and typus in ('movie', 'episode') + and not currentFile.startswith('http')): try: - kodiid = result["result"]["item"][key] - except (TypeError, KeyError): - pass - # Kodi might return -1 for last element - if kodiid in (None, -1) and typus in ('movie', 'episode'): - log('Could not get Kodi id directly. Kodi said: %s' - % result, 1) - log('Trying to get Kodi id from the items name', 1) - with kodidb.GetKodiDB('video') as kodi_db: - kodiid = kodi_db.getIdFromTitle(data.get('item')) + filename = currentFile.rsplit('/', 1)[1] + path = currentFile.rsplit('/', 1)[0] + '/' + except IndexError: + filename = currentFile.rsplit('\\', 1)[1] + path = currentFile.rsplit('\\', 1)[0] + '\\' + log('Trying to figure out playing item from filename: %s and ' + 'path: %s' % (filename, path), 1) + with kodidb.GetKodiDB('video') as kodi_db: + try: + kodiid, typus = kodi_db.getIdFromFilename(filename, path) + except TypeError: + log('Aborting playback report', 1) + return - if kodiid in (None, -1): - log("Skip playstate update. No unique Kodi title found" - " for %s" % data.get('item'), 0) + if plexid is None: + # Get Plex' item id + with embydb.GetEmbyDB() as emby_db: + emby_dbitem = emby_db.getItem_byKodiId(kodiid, typus) + try: + plexid = emby_dbitem[0] + except TypeError: + log("No Plex id returned for kodiid %s" % kodiid, 1) + log('Aborting playback report', 1) return - - # Get Plex' item id - with embydb.GetEmbyDB() as emby_db: - emby_dbitem = emby_db.getItem_byKodiId(kodiid, typus) - try: - plexid = emby_dbitem[0] - except TypeError: - log("No Plex id returned for kodiid %s" % kodiid, 1) - log('Aborting playback report', 1) - return - log("Found Plex id %s for Kodi id %s" % (plexid, kodiid), 1) + log("Found Plex id %s for Kodi id %s for type %s" + % (plexid, kodiid, typus), 1) # Set some stuff if Kodi initiated playback if ((utils.settings('useDirectPaths') == "1" and not typus == "song") or (typus == "song" and utils.settings('enableMusic') == "true")): - if self.StartDirectPath(plexid, typus, currentFile) is False: + if self.StartDirectPath(plexid, + typus, + utils.tryEncode(currentFile)) is False: log('Could not initiate monitoring; aborting', -1) return # Save currentFile for cleanup later and to be able to access refs - window('plex_lastPlayedFiled', value=utils.tryDecode(currentFile)) + window('plex_lastPlayedFiled', value=currentFile) window('Plex_currently_playing_itemid', value=plexid) - window("emby_%s.itemid" % currentFile, value=plexid) + window("emby_%s.itemid" % utils.tryEncode(currentFile), value=plexid) log('Finish playback startup', 1) def StartDirectPath(self, plexid, type, currentFile): diff --git a/resources/lib/utils.py b/resources/lib/utils.py index 5edae042..665ccd09 100644 --- a/resources/lib/utils.py +++ b/resources/lib/utils.py @@ -941,6 +941,9 @@ def tryEncode(uniString, encoding='utf-8'): uniString = uniString.encode(encoding, "ignore") except TypeError: uniString = uniString.encode() + except UnicodeDecodeError: + # already encoded + pass return uniString