# -*- coding: utf-8 -*- ################################################################################################# import logging import sqlite3 import xbmc ################################################################################################# log = logging.getLogger("EMBY."+__name__) KODI = xbmc.getInfoLabel('System.BuildVersion')[:2] ################################################################################################# def video_database(): db_version = { '13': 78, # Gotham '14': 90, # Helix '15': 93, # Isengard '16': 99, # Jarvis '17': 107 # Krypton } path = xbmc.translatePath("special://database/MyVideos%s.db" % db_version.get(KODI, "")).decode('utf-8') return path def music_database(): db_version = { '13': 46, # Gotham '14': 48, # Helix '15': 52, # Isengard '16': 56, # Jarvis '17': 60 # Krypton } path = xbmc.translatePath("special://database/MyMusic%s.db" % db_version.get(KODI, "")).decode('utf-8') return path class DatabaseConn(object): # To be called as context manager - i.e. with DatabaseConn() as dbconn def __init__(self, database_file="video", commit_mode=""): """ database_file can be custom: emby, texture, music, video, custom like :memory: or path commit_mode set to None to autocommit (isolation_level). See python documentation. """ self.db_file = database_file self.commit_mode = commit_mode def __enter__(self): # Open the connection self.path = self._SQL(self.db_file) log.warn("opening database: %s", self.path) self.conn = sqlite3.connect(self.path, isolation_level=self.commit_mode, timeout=20) return self.conn def _SQL(self, media_type): if media_type == "emby": return xbmc.translatePath("special://database/emby.db").decode('utf-8') elif media_type == "texture": return xbmc.translatePath("special://database/Textures13.db").decode('utf-8') elif media_type == "music": return music_database() elif media_type == "video": return video_database() else: # custom path return self.db_file def __exit__(self, exc_type, exc_val, exc_tb): # Close the connection if exc_type is not None: # Errors were raised in the with statement log.error("rollback: Type: %s Value: %s", exc_type, exc_val) self.conn.rollback() elif self.commit_mode is not None: log.warn("commit: %s", self.path) self.conn.commit() self.conn.close() def query(execute_query, connection=None, conn_type=None, *args): """ connection is sqlite.connect conn_type is only required if a connection is not provided *args are tuple values that contain the corresponding data for the query i.e args_executemany = (('value1', 'value2'),('value1', 'value2')) args_execute = ('value1', 'value2') tip: to build args_executemany, build a list of sets [(v1,v2),(v1,v2)], then pass it as *args """ if connection is None: if conn_type is None: return False else: connection = DatabaseConn(conn_type) attempts = 3 while True: try: with connection as conn: # raise sqlite3.OperationalError("database is locked") if not args: return conn.execute(query) elif isinstance(args[0], tuple): # Multiple entries for the same query return conn.executemany(query, args) else: return conn.execute(query, args) except sqlite3.OperationalError as e: if "database is locked" in str(e): # Database is locked, retry attempts -= 1 xbmc.sleep(1000) else: raise if not attempts: return False