From 150229061bc7c9a01bb5aabce9ea727087a00f3f Mon Sep 17 00:00:00 2001 From: croneter Date: Thu, 8 Nov 2018 15:15:52 +0100 Subject: [PATCH] Reduce Python DB overhead --- resources/lib/kodidb_functions.py | 654 +++++++++++++----------------- resources/lib/kodimonitor.py | 18 +- resources/lib/plex_db/common.py | 50 +-- resources/lib/plex_db/tvshows.py | 39 +- resources/lib/sync.py | 2 +- resources/lib/utils.py | 14 +- 6 files changed, 335 insertions(+), 442 deletions(-) diff --git a/resources/lib/kodidb_functions.py b/resources/lib/kodidb_functions.py index cb3cc453..24c1f386 100644 --- a/resources/lib/kodidb_functions.py +++ b/resources/lib/kodidb_functions.py @@ -110,16 +110,16 @@ class KodiDBMethods(object): self.cursor.execute("SELECT COALESCE(MAX(idPath),0) FROM path") pathid = self.cursor.fetchone()[0] + 1 datetime = utils.unix_date_to_kodi(utils.unix_timestamp()) - query = ''' - INSERT INTO path(idPath, strPath, dateAdded) - VALUES (?, ?, ?) - ''' - self.cursor.execute(query, (pathid, parentpath, datetime)) + self.cursor.execute(''' + INSERT INTO path(idPath, strPath, dateAdded) + VALUES (?, ?, ?) + ''', + (pathid, parentpath, datetime)) if parentpath != path: # In case we end up having media in the filesystem root, C:\ parent_id = self.parent_path_id(parentpath) - query = 'UPDATE path SET idParentPath = ? WHERE idPath = ?' - self.cursor.execute(query, (parent_id, pathid)) + self.cursor.execute('UPDATE path SET idParentPath = ? WHERE idPath = ?', + (parent_id, pathid)) return pathid def add_video_path(self, path, date_added=None, id_parent_path=None, @@ -132,21 +132,25 @@ class KodiDBMethods(object): WILL activate noUpdate for the path! """ - if path is None: - path = '' - query = 'SELECT idPath FROM path WHERE strPath = ? LIMIT 1' - self.cursor.execute(query, (path,)) + path = '' if path is None else path + self.cursor.execute('SELECT idPath FROM path WHERE strPath = ? LIMIT 1', + (path, )) try: pathid = self.cursor.fetchone()[0] except TypeError: self.cursor.execute("SELECT COALESCE(MAX(idPath),0) FROM path") pathid = self.cursor.fetchone()[0] + 1 - query = ''' - INSERT INTO path(idPath, strPath, dateAdded, idParentPath, - strContent, strScraper, noUpdate) - VALUES (?, ?, ?, ?, ?, ?, ?) - ''' - self.cursor.execute(query, + self.cursor.execute(''' + INSERT INTO path( + idPath, + strPath, + dateAdded, + idParentPath, + strContent, + strScraper, + noUpdate) + VALUES (?, ?, ?, ?, ?, ?, ?) + ''', (pathid, path, date_added, id_parent_path, content, scraper, 1)) return pathid @@ -158,20 +162,19 @@ class KodiDBMethods(object): Set hash_string to something unicode to set the strHash attribute """ # SQL won't return existing paths otherwise - if path is None: - path = '' - query = 'SELECT idPath FROM path WHERE strPath = ?' - self.cursor.execute(query, (path,)) + path = '' if path is None else path + self.cursor.execute('SELECT idPath FROM path WHERE strPath = ?', + (path,)) try: pathid = self.cursor.fetchone()[0] except TypeError: self.cursor.execute("SELECT COALESCE(MAX(idPath),0) FROM path") pathid = self.cursor.fetchone()[0] + 1 - query = ''' - INSERT INTO path(idPath, strPath, strHash) - VALUES (?, ?, ?) - ''' - self.cursor.execute(query, (pathid, path, hash_string)) + self.cursor.execute(''' + INSERT INTO path(idPath, strPath, strHash) + VALUES (?, ?, ?) + ''', + (pathid, path, hash_string)) return pathid def get_path(self, path): @@ -179,12 +182,11 @@ class KodiDBMethods(object): Returns the idPath from the path table for path [unicode] or None """ self.cursor.execute('SELECT idPath FROM path WHERE strPath = ?', - (path,)) + (path, )) try: - pathid = self.cursor.fetchone()[0] + return self.cursor.fetchone()[0] except TypeError: - pathid = None - return pathid + pass def add_file(self, filename, path_id, date_added): """ @@ -208,18 +210,16 @@ class KodiDBMethods(object): def obsolete_file_ids(self): """ - Returns a list of (idFile,) tuples (ints) of all Kodi file ids that do - not have a dateAdded set (dateAdded NULL) and the filename start with + Returns a generator for idFile of all Kodi file ids that do not have a + dateAdded set (dateAdded NULL) and the filename start with 'plugin://plugin.video.plexkodiconnect' These entries should be deleted as they're created falsely by Kodi. """ - query = ''' + return (x[0] for x in self.cursor.execute(''' SELECT idFile FROM files WHERE dateAdded IS NULL AND strFilename LIKE \'plugin://plugin.video.plexkodiconnect%\' - ''' - self.cursor.execute(query) - return self.cursor.fetchall() + ''')) def show_id_from_path(self, path): """ @@ -231,13 +231,12 @@ class KodiDBMethods(object): path_id = self.cursor.fetchone()[0] except TypeError: return - query = 'SELECT idShow FROM tvshowlinkpath WHERE idPath = ? LIMIT 1' - self.cursor.execute(query, (path_id, )) + self.cursor.execute('SELECT idShow FROM tvshowlinkpath WHERE idPath = ? LIMIT 1', + (path_id, )) try: - show_id = self.cursor.fetchone()[0] + return self.cursor.fetchone()[0] except TypeError: - show_id = None - return show_id + pass def remove_file(self, file_id, remove_orphans=True, plex_type=None): """ @@ -251,16 +250,14 @@ class KodiDBMethods(object): """ if not state.DIRECT_PATHS and plex_type == v.PLEX_TYPE_EPISODE: # Hack for the 2 entries for episodes for addon paths - query = 'SELECT strFilename FROM files WHERE idFile = ? LIMIT 1' - self.cursor.execute(query, (file_id, )) + self.cursor.execute('SELECT strFilename FROM files WHERE idFile = ? LIMIT 1', + (file_id, )) filename = self.cursor.fetchone() if not filename: LOG.error('Could not find file_id %s', file_id) return - query = 'SELECT idFile FROM files WHERE strFilename = ? LIMIT 2' - self.cursor.execute(query, (filename[0], )) - file_ids = self.cursor.fetchall() - for new_id in file_ids: + for new_id in self.cursor.execute('SELECT idFile FROM files WHERE strFilename = ? LIMIT 2', + (filename[0], )): self.remove_file(new_id[0], remove_orphans=remove_orphans) return @@ -282,8 +279,8 @@ class KodiDBMethods(object): (file_id,)) if remove_orphans: # Delete orphaned path entry - query = 'SELECT idFile FROM files WHERE idPath = ? LIMIT 1' - self.cursor.execute(query, (path_id,)) + self.cursor.execute('SELECT idFile FROM files WHERE idPath = ? LIMIT 1', + (path_id,)) if self.cursor.fetchone() is None: self.cursor.execute('DELETE FROM path WHERE idPath = ?', (path_id,)) @@ -291,67 +288,59 @@ class KodiDBMethods(object): def _modify_link_and_table(self, kodi_id, kodi_type, entries, link_table, table, key, first_id=None): first_id = first_id if first_id is not None else 1 - query = ''' - SELECT %s FROM %s WHERE name = ? COLLATE NOCASE LIMIT 1 - ''' % (key, table) - query_id = ('SELECT COALESCE(MAX(%s), %s) FROM %s' - % (key, first_id - 1, table)) - query_new = ('INSERT INTO %s(%s, name) values(?, ?)' - % (table, key)) entry_ids = [] for entry in entries: - self.cursor.execute(query, (entry,)) + self.cursor.execute(''' + SELECT %s FROM %s WHERE name = ? COLLATE NOCASE LIMIT 1 + ''' % (key, table), (entry, )) try: entry_id = self.cursor.fetchone()[0] except TypeError: - self.cursor.execute(query_id) + self.cursor.execute('SELECT COALESCE(MAX(%s), %s) FROM %s' + % (key, first_id - 1, table)) entry_id = self.cursor.fetchone()[0] + 1 - self.cursor.execute(query_new, (entry_id, entry)) + self.cursor.execute('INSERT INTO %s(%s, name) values(?, ?)' + % (table, key), (entry_id, entry)) finally: entry_ids.append(entry_id) # Now process the ids obtained from the names # Get the existing, old entries - query = ('SELECT %s FROM %s WHERE media_id = ? AND media_type = ?' - % (key, link_table)) - self.cursor.execute(query, (kodi_id, kodi_type)) - old_entries = self.cursor.fetchall() outdated_entries = [] - for entry_id in old_entries: + for entry_id in self.cursor.execute('SELECT %s FROM %s WHERE media_id = ? AND media_type = ?' + % (key, link_table), (kodi_id, kodi_type)): try: entry_ids.remove(entry_id[0]) except ValueError: outdated_entries.append(entry_id[0]) # Add all new entries that haven't already been added - query = 'INSERT INTO %s VALUES (?, ?, ?)' % link_table for entry_id in entry_ids: try: - self.cursor.execute(query, (entry_id, kodi_id, kodi_type)) + self.cursor.execute('INSERT INTO %s VALUES (?, ?, ?)' % link_table, + (entry_id, kodi_id, kodi_type)) except IntegrityError: LOG.info('IntegrityError: skipping entry %s for table %s', entry_id, link_table) # Delete all outdated references in the link table. Also check whether # we need to delete orphaned entries in the master table - query = ''' - DELETE FROM %s WHERE %s = ? AND media_id = ? AND media_type = ? - ''' % (link_table, key) - query_rem = 'SELECT %s FROM %s WHERE %s = ?' % (key, link_table, key) - query_delete = 'DELETE FROM %s WHERE %s = ?' % (table, key) for entry_id in outdated_entries: - self.cursor.execute(query, (entry_id, kodi_id, kodi_type)) - self.cursor.execute(query_rem, (entry_id,)) + self.cursor.execute(''' + DELETE FROM %s WHERE %s = ? AND media_id = ? AND media_type = ? + ''' % (link_table, key), (entry_id, kodi_id, kodi_type)) + self.cursor.execute('SELECT %s FROM %s WHERE %s = ?' % (key, link_table, key), + (entry_id, )) if self.cursor.fetchone() is None: # Delete in the original table because entry is now orphaned - self.cursor.execute(query_delete, (entry_id,)) + self.cursor.execute('DELETE FROM %s WHERE %s = ?' % (table, key), + (entry_id, )) def modify_countries(self, kodi_id, kodi_type, countries=None): """ Writes a country (string) in the list countries into the Kodi DB. Will also delete any orphaned country entries. """ - countries = countries if countries else [] self._modify_link_and_table(kodi_id, kodi_type, - countries, + countries if countries else [], 'country_link', 'country', 'country_id') @@ -361,10 +350,9 @@ class KodiDBMethods(object): Writes a country (string) in the list countries into the Kodi DB. Will also delete any orphaned country entries. """ - genres = genres if genres else [] self._modify_link_and_table(kodi_id, kodi_type, - genres, + genres if genres else [], 'genre_link', 'genre', 'genre_id') @@ -374,10 +362,9 @@ class KodiDBMethods(object): Writes a country (string) in the list countries into the Kodi DB. Will also delete any orphaned country entries. """ - studios = studios if studios else [] self._modify_link_and_table(kodi_id, kodi_type, - studios, + studios if studios else [], 'studio_link', 'studio', 'studio_id') @@ -387,10 +374,9 @@ class KodiDBMethods(object): Writes a country (string) in the list countries into the Kodi DB. Will also delete any orphaned country entries. """ - tags = tags if tags else [] self._modify_link_and_table(kodi_id, kodi_type, - tags, + tags if tags else [], 'tag_link', 'tag', 'tag_id') @@ -401,10 +387,10 @@ class KodiDBMethods(object): for the elmement kodi_id, kodi_type. Will also delete a freshly orphaned actor entry. """ - people = people if people else {'actor': [], - 'director': [], - 'writer': []} - for kind, people_list in people.iteritems(): + for kind, people_list in (people if people else + {'actor': [], + 'director': [], + 'writer': []}).iteritems(): self._modify_people_kind(kodi_id, kodi_type, kind, people_list) def _modify_people_kind(self, kodi_id, kodi_type, kind, people_list): @@ -494,7 +480,7 @@ class KodiDBMethods(object): self.cursor.execute('SELECT actor_id FROM actor WHERE name=? LIMIT 1', (name,)) try: - actor_id = self.cursor.fetchone()[0] + return self.cursor.fetchone()[0] except TypeError: # Not yet in actor DB, add person self.cursor.execute('SELECT COALESCE(MAX(actor_id),0) FROM actor') @@ -508,7 +494,7 @@ class KodiDBMethods(object): 'actor', 'thumb', self.cursor) - return actor_id + return actor_id def get_art(self, kodi_id, kodi_type): """ @@ -525,8 +511,8 @@ class KodiDBMethods(object): Missing fanart will not appear in the dict. 'landscape' and 'icon' might be implemented in the future. """ - query = 'SELECT type, url FROM art WHERE media_id=? AND media_type=?' - self.cursor.execute(query, (kodi_id, kodi_type)) + self.cursor.execute('SELECT type, url FROM art WHERE media_id=? AND media_type=?', + (kodi_id, kodi_type)) return dict(self.cursor.fetchall()) def modify_streams(self, fileid, streamdetails=None, runtime=None): @@ -540,52 +526,30 @@ class KodiDBMethods(object): if not streamdetails: return for videotrack in streamdetails['video']: - query = ''' + self.cursor.execute(''' INSERT INTO streamdetails( idFile, iStreamType, strVideoCodec, fVideoAspect, iVideoWidth, iVideoHeight, iVideoDuration ,strStereoMode) VALUES (?, ?, ?, ?, ?, ?, ?, ?) - ''' - self.cursor.execute(query, - (fileid, 0, videotrack['codec'], - videotrack['aspect'], videotrack['width'], - videotrack['height'], runtime, - videotrack['video3DFormat'])) + ''', (fileid, 0, videotrack['codec'], + videotrack['aspect'], videotrack['width'], + videotrack['height'], runtime, + videotrack['video3DFormat'])) for audiotrack in streamdetails['audio']: - query = ''' + self.cursor.execute(''' INSERT INTO streamdetails( idFile, iStreamType, strAudioCodec, iAudioChannels, strAudioLanguage) VALUES (?, ?, ?, ?, ?) - ''' - self.cursor.execute(query, - (fileid, 1, audiotrack['codec'], - audiotrack['channels'], - audiotrack['language'])) + ''', (fileid, 1, audiotrack['codec'], + audiotrack['channels'], + audiotrack['language'])) for subtitletrack in streamdetails['subtitle']: - query = ''' + self.cursor.execute(''' INSERT INTO streamdetails(idFile, iStreamType, strSubtitleLanguage) VALUES (?, ?, ?) - ''' - self.cursor.execute(query, (fileid, 2, subtitletrack)) - - def resume_points(self): - """ - VIDEOS - - Returns all Kodi idFile that have a resume point set (not unwatched - ones or items that have already been completely watched) - """ - query = ''' - SELECT idFile - FROM bookmark - ''' - rows = self.cursor.execute(query) - ids = [] - for row in rows: - ids.append(row[0]) - return ids + ''', (fileid, 2, subtitletrack)) def video_id_from_filename(self, filename, path): """ @@ -595,27 +559,26 @@ class KodiDBMethods(object): Returns None if not found OR if too many entries were found """ - query = 'SELECT idFile, idPath FROM files WHERE strFilename = ?' - self.cursor.execute(query, (filename,)) + self.cursor.execute('SELECT idFile, idPath FROM files WHERE strFilename = ?', + (filename,)) files = self.cursor.fetchall() if len(files) == 0: LOG.info('Did not find any file, abort') return - query = '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],)) + self.cursor.execute('SELECT strPath FROM path WHERE idPath = ?', + (file[1], )) try: path_str = self.cursor.fetchone()[0] except TypeError: # idPath not found; skip continue # For whatever reason, double might have become triple - path_str = path_str.replace('///', '//') - path_str = path_str.replace('\\\\\\', '\\\\') + path_str = path_str.replace('///', '//').replace('\\\\\\', '\\\\') if path_str == path: result.append(file[0]) if len(result) == 0: @@ -637,8 +600,7 @@ class KodiDBMethods(object): typus = v.KODI_TYPE_MOVIE except TypeError: # Try tv shows next - query = 'SELECT idEpisode FROM episode WHERE idFile = ?' - self.cursor.execute(query, + self.cursor.execute('SELECT idEpisode FROM episode WHERE idFile = ?', (file_id, )) try: movie_id = self.cursor.fetchone()[0] @@ -653,23 +615,15 @@ class KodiDBMethods(object): Returns the Kodi song_id from the Kodi music database or None if not found OR something went wrong. """ - query = ''' - SELECT idPath - FROM path - WHERE strPath = ? - ''' - self.cursor.execute(query, (path,)) + self.cursor.execute('SELECT idPath FROM path WHERE strPath = ?', + (path,)) path_ids = self.cursor.fetchall() if len(path_ids) != 1: LOG.debug('Found wrong number of path ids: %s for path %s, abort', path_ids, path) return - query = ''' - SELECT idSong - FROM song - WHERE strFileName = ? AND idPath = ? - ''' - self.cursor.execute(query, (filename, path_ids[0][0])) + self.cursor.execute('SELECT idSong FROM song WHERE strFileName = ? AND idPath = ?', + (filename, path_ids[0][0])) song_ids = self.cursor.fetchall() if len(song_ids) != 1: LOG.info('Found wrong number of songs %s, abort', song_ids) @@ -681,33 +635,23 @@ class KodiDBMethods(object): Returns the first resume point in seconds (int) if found, else None for the Kodi file_id provided """ - query = ''' - SELECT timeInSeconds - FROM bookmark - WHERE idFile = ? - ''' - self.cursor.execute(query, (file_id,)) - resume = self.cursor.fetchone() + self.cursor.execute('SELECT timeInSeconds FROM bookmark WHERE idFile = ? LIMIT 1', + (file_id,)) try: - resume = resume[0] + return self.cursor.fetchone()[0] except TypeError: - resume = None - return resume + pass def get_playcount(self, file_id): """ Returns the playcount for the item file_id or None if not found """ - query = ''' - SELECT playCount FROM files - WHERE idFile = ? LIMIT 1 - ''' - self.cursor.execute(query, (file_id, )) + self.cursor.execute('SELECT playCount FROM files WHERE idFile = ? LIMIT 1', + (file_id, )) try: - answ = self.cursor.fetchone()[0] + return self.cursor.fetchone()[0] except TypeError: - answ = None - return answ + pass def set_resume(self, file_id, resume_seconds, total_seconds, playcount, dateplayed, plex_type): @@ -719,20 +663,10 @@ class KodiDBMethods(object): # Need to make sure to set a SECOND bookmark entry for another, # second file_id that points to the path .tvshows instead of # .tvshows/= 18: - query = ''' + kodi_db.cursor.execute(''' INSERT OR REPLACE INTO versiontagscan( - idVersion, iNeedsScan, lastscanned) + idVersion, + iNeedsScan, + lastscanned) VALUES (?, ?, ?) - ''' - kodi_db.cursor.execute(query, (v.DB_MUSIC_VERSION[v.KODIVERSION], - 0, - utils.unix_date_to_kodi( - utils.unix_timestamp()))) + ''', (v.DB_MUSIC_VERSION[v.KODIVERSION], + 0, + utils.unix_date_to_kodi(utils.unix_timestamp()))) def reset_cached_images(): @@ -1290,8 +1196,8 @@ def reset_cached_images(): new_path = path_ops.translate_path('special://thumbnails/%s' % path) path_ops.makedirs(path_ops.encode_path(new_path)) with GetKodiDB('texture') as kodi_db: - query = 'SELECT tbl_name FROM sqlite_master WHERE type=?' - kodi_db.cursor.execute(query, ('table', )) + kodi_db.cursor.execute('SELECT tbl_name FROM sqlite_master WHERE type=?', + ('table', )) rows = kodi_db.cursor.fetchall() for row in rows: if row[0] != 'version': @@ -1304,13 +1210,12 @@ def wipe_dbs(music=True): music sync is enabled) """ LOG.warn('Wiping Kodi databases!') - query = "SELECT name FROM sqlite_master WHERE type = 'table'" kinds = ['video', 'texture'] if music: kinds.append('music') for db in kinds: with GetKodiDB(db) as kodi_db: - kodi_db.cursor.execute(query) + kodi_db.cursor.execute("SELECT name FROM sqlite_master WHERE type = 'table'") tables = kodi_db.cursor.fetchall() tables = [i[0] for i in tables] if 'version' in tables: @@ -1318,8 +1223,7 @@ def wipe_dbs(music=True): if 'versiontagscan' in tables: tables.remove('versiontagscan') for table in tables: - delete_query = 'DELETE FROM %s' % table - kodi_db.cursor.execute(delete_query) + kodi_db.cursor.execute('DELETE FROM %s' % table) setup_kodi_default_entries() # Make sure Kodi knows we wiped the databases import xbmc diff --git a/resources/lib/kodimonitor.py b/resources/lib/kodimonitor.py index 280afc97..935ecf62 100644 --- a/resources/lib/kodimonitor.py +++ b/resources/lib/kodimonitor.py @@ -599,16 +599,10 @@ def _clean_file_table(): This function tries for at most 5 seconds to clean the file table. """ LOG.debug('Start cleaning Kodi files table') - i = 0 - while i < 100 and not state.STOP_PKC: - with kodidb.GetKodiDB('video') as kodi_db: - files = kodi_db.obsolete_file_ids() - if files: - break - i += 1 - xbmc.sleep(50) - with kodidb.GetKodiDB('video') as kodi_db: - for file_id in files: - LOG.debug('Removing obsolete Kodi file_id %s', file_id) - kodi_db.remove_file(file_id[0], remove_orphans=False) + xbmc.sleep(2000) + with kodidb.GetKodiDB('video') as kodi_db_1: + with kodidb.GetKodiDB('video') as kodi_db_2: + for file_id in kodi_db_1.obsolete_file_ids(): + LOG.debug('Removing obsolete Kodi file_id %s', file_id) + kodi_db_2.remove_file(file_id, remove_orphans=False) LOG.debug('Done cleaning up Kodi file table') diff --git a/resources/lib/plex_db/common.py b/resources/lib/plex_db/common.py index bd9a585b..a56d0326 100644 --- a/resources/lib/plex_db/common.py +++ b/resources/lib/plex_db/common.py @@ -36,8 +36,8 @@ class PlexDBBase(object): """ FAST method to check whether a plex_id has already been recorded """ - query = 'SELECT plex_id FROM %s WHERE plex_id = ?' % plex_type - self.cursor.execute(query, (plex_id, )) + self.cursor.execute('SELECT plex_id FROM %s WHERE plex_id = ?' % plex_type, + (plex_id, )) return self.cursor.fetchone() is not None def item_by_id(self, plex_id, plex_type=None): @@ -80,9 +80,9 @@ class PlexDBBase(object): """ if kodi_type not in SUPPORTED_KODI_TYPES: return - query = ('SELECT * from %s WHERE kodi_id = ? LIMIT 1' - % v.PLEX_TYPE_FROM_KODI_TYPE[kodi_type]) - self.cursor.execute(query, (kodi_id, )) + self.cursor.execute('SELECT * from %s WHERE kodi_id = ? LIMIT 1' + % v.PLEX_TYPE_FROM_KODI_TYPE[kodi_type], + (kodi_id, )) method = getattr(self, 'entry_to_%s' % v.PLEX_TYPE_FROM_KODI_TYPE[kodi_type]) return method(self.cursor.fetchone()) @@ -90,16 +90,16 @@ class PlexDBBase(object): """ Returns an iterator for all items where the last_sync is NOT identical """ - query = 'SELECT plex_id FROM %s WHERE last_sync <> ?' % plex_type - self.cursor.execute(query, (last_sync, )) - return (x[0] for x in self.cursor) + return (x[0] for x in + self.cursor.execute('SELECT plex_id FROM %s WHERE last_sync <> ?' % plex_type, + (last_sync, ))) def checksum(self, plex_id, plex_type): """ Returns the checksum for plex_id """ - query = 'SELECT checksum FROM %s WHERE plex_id = ?' % plex_type - self.cursor.execute(query, (plex_id, )) + self.cursor.execute('SELECT checksum FROM %s WHERE plex_id = ? LIMIT 1' % plex_type, + (plex_id, )) try: return self.cursor.fetchone()[0] except TypeError: @@ -109,39 +109,36 @@ class PlexDBBase(object): """ Sets a new timestamp for plex_id """ - query = 'UPDATE %s SET last_sync = ? WHERE plex_id = ?' % plex_type - self.cursor.execute(query, (last_sync, plex_id)) + self.cursor.execute('UPDATE %s SET last_sync = ? WHERE plex_id = ?' % plex_type, + (last_sync, plex_id)) def remove(self, plex_id, plex_type): """ Removes the item from our Plex db """ - query = 'DELETE FROM ? WHERE plex_id = ?' % plex_type - self.cursor.execute(query, (plex_id, )) + self.cursor.execute('DELETE FROM ? WHERE plex_id = ?' % plex_type, (plex_id, )) def every_plex_id(self, plex_type): """ Returns an iterator for plex_type for every single plex_id """ - query = 'SELECT plex_id from %s' % plex_type - self.cursor.execute(query) - return (x[0] for x in self.cursor) + return (x[0] for x in + self.cursor.execute('SELECT plex_id from %s' % plex_type)) def missing_fanart(self, plex_type): """ Returns an iterator for plex_type for all plex_id, where fanart_synced has not yet been set to 1 """ - query = 'SELECT plex_id from %s WHERE fanart_synced = 0' % plex_type - self.cursor.execute(query) - return (x[0] for x in self.cursor) + return (x[0] for x in + self.cursor.execute('SELECT plex_id from %s WHERE fanart_synced = 0' % plex_type)) def set_fanart_synced(self, plex_id, plex_type): """ Toggles fanart_synced to 1 for plex_id """ - query = 'UPDATE %s SET fanart_synced = 1 WHERE plex_id = ?' % plex_type - self.cursor.execute(query, (plex_id, )) + self.cursor.execute('UPDATE %s SET fanart_synced = 1 WHERE plex_id = ?' % plex_type, + (plex_id, )) def initialize(): @@ -258,11 +255,8 @@ def wipe(): """ Completely resets the Plex database """ - query = "SELECT name FROM sqlite_master WHERE type = 'table'" with PlexDBBase() as plexdb: - plexdb.cursor.execute(query) - tables = plexdb.cursor.fetchall() - tables = [i[0] for i in tables] + plexdb.cursor.execute("SELECT name FROM sqlite_master WHERE type = 'table'") + tables = [i[0] for i in plexdb.cursor.fetchall()] for table in tables: - delete_query = 'DROP table IF EXISTS %s' % table - plexdb.cursor.execute(delete_query) + plexdb.cursor.execute('DROP table IF EXISTS %s' % table) diff --git a/resources/lib/plex_db/tvshows.py b/resources/lib/plex_db/tvshows.py index d6ae23d4..4994a7d5 100644 --- a/resources/lib/plex_db/tvshows.py +++ b/resources/lib/plex_db/tvshows.py @@ -10,7 +10,8 @@ class TVShows(object): """ Appends or replaces tv show entry into the plex table """ - query = ''' + self.cursor.execute( + ''' INSERT OR REPLACE INTO show( plex_id, checksum, @@ -20,9 +21,7 @@ class TVShows(object): fanart_synced, last_sync) VALUES (?, ?, ?, ?, ?, ?, ?) - ''' - self.cursor.execute( - query, + ''', (plex_id, checksum, section_id, @@ -36,7 +35,8 @@ class TVShows(object): """ Appends or replaces an entry into the plex table """ - query = ''' + self.cursor.execute( + ''' INSERT OR REPLACE INTO season( plex_id, checksum, @@ -47,9 +47,7 @@ class TVShows(object): fanart_synced, last_sync) VALUES (?, ?, ?, ?, ?, ?, ?, ?) - ''' - self.cursor.execute( - query, + ''', (plex_id, checksum, section_id, @@ -65,7 +63,8 @@ class TVShows(object): """ Appends or replaces an entry into the plex table """ - query = ''' + self.cursor.execute( + ''' INSERT OR REPLACE INTO episode( plex_id, checksum, @@ -80,9 +79,7 @@ class TVShows(object): fanart_synced, last_sync) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - ''' - self.cursor.execute( - query, + ''', (plex_id, checksum, section_id, @@ -236,24 +233,24 @@ class TVShows(object): Returns an iterator for all episodes that have a parent season_id with a value of plex_id """ - self.cursor.execute('SELECT * FROM episode WHERE season_id = ?', - (plex_id, )) - return (self.entry_to_episode(x) for x in self.cursor) + return (self.entry_to_episode(x) for x in + self.cursor.execute('SELECT * FROM episode WHERE season_id = ?', + (plex_id, ))) def episode_by_show(self, plex_id): """ Returns an iterator for all episodes that have a grandparent show_id with a value of plex_id """ - self.cursor.execute('SELECT * FROM episode WHERE show_id = ?', - (plex_id, )) - return (self.entry_to_episode(x) for x in self.cursor) + return (self.entry_to_episode(x) for x in + self.cursor.execute('SELECT * FROM episode WHERE show_id = ?', + (plex_id, ))) def season_by_show(self, plex_id): """ Returns an iterator for all seasons that have a parent show_id with a value of plex_id """ - self.cursor.execute('SELECT * FROM season WHERE show_id = ?', - (plex_id, )) - return (self.entry_to_season(x) for x in self.cursor) + return (self.entry_to_season(x) for x in + self.cursor.execute('SELECT * FROM season WHERE show_id = ?', + (plex_id, ))) diff --git a/resources/lib/sync.py b/resources/lib/sync.py index ba54a8a9..49e1bdb6 100644 --- a/resources/lib/sync.py +++ b/resources/lib/sync.py @@ -235,7 +235,7 @@ class Sync(backgroundthread.KillableThread): # Ensure that Plex DB is set-up plex_db.initialize() # Hack to speed up look-ups for actors (giant table!) - utils.create_actor_db_index() + utils.create_kodi_db_indicees() with kodidb.GetKodiDB('video') as kodi_db: # Setup the paths for addon-paths (even when using direct paths) kodi_db.setup_path_table() diff --git a/resources/lib/utils.py b/resources/lib/utils.py index 38bd6965..8fe22040 100644 --- a/resources/lib/utils.py +++ b/resources/lib/utils.py @@ -493,20 +493,24 @@ def kodi_sql(media_type=None): return conn -def create_actor_db_index(): +def create_kodi_db_indicees(): """ Index the "actors" because we got a TON - speed up SELECT and WHEN """ + return conn = kodi_sql('video') cursor = conn.cursor() try: - cursor.execute(""" - CREATE UNIQUE INDEX index_name - ON actor (name); - """) + cursor.execute('CREATE UNIQUE INDEX ix_files_2 ON files (idFile);') except OperationalError: # Index already exists pass + # Already used in Kodi >=17: CREATE UNIQUE INDEX ix_actor_1 ON actor (name) + # try: + # cursor.execute('CREATE UNIQUE INDEX ix_pkc_actor_index ON actor (name);') + # except OperationalError: + # # Index already exists + # pass conn.commit() conn.close()