diff --git a/dbtest.py b/dbtest.py new file mode 100644 index 0000000..51fe788 --- /dev/null +++ b/dbtest.py @@ -0,0 +1,66 @@ +import sys +sys.path.insert(0,'lib') +import dbutils +import libsonic +import time + + +db = None +connection = None + +db_filename = "subsonic_sqlite.db" + +def get_db(): + global db_filename + global db + print("Getting DB %s"%db_filename) + try: + db = dbutils.SQLiteDatabase(db_filename) + except Exception as e: + print("Connecting to DB failed: %s"%e) + return db + +def get_connection(): + global connection + + if connection==None: + connected = False + # Create connection + try: + connection = libsonic.Connection( + baseUrl="http://192.168.25.16", + username="warwick.harris", + password="ducatiMonsterSoundsGreat$", + port="4040", + apiVersion="1.15.1", + insecure=False, + legacyAuth=False, + useGET=False, + ) + connected = connection.ping() + except: + pass + + if connected==False: + print('Connection error') + return False + + return connection + +db = get_db() +connection = get_connection() + +#cursor = db.get_cursor() +#cursor.execute("SELECT name FROM sqlite_master WHERE type='table'") +#print(cursor.fetchall()) +artist_id = 635 +artist_info = connection.getArtistInfo2(artist_id) +#print("Artist info: %s"%artist_info) +print(db.update_artist(artist_id, artist_info, time.time())) +print(db.get_artist_info(artist_id)) +print(db.update_artist(artist_id, "replace", time.time())) +print(db.get_artist_info(1)) + + + +db.close() diff --git a/dbutils.py b/dbutils.py new file mode 100644 index 0000000..e69de29 diff --git a/lib/dbutils/__init__.py b/lib/dbutils/__init__.py new file mode 100644 index 0000000..1171642 --- /dev/null +++ b/lib/dbutils/__init__.py @@ -0,0 +1,7 @@ +""" +Databse utilities for plugin.audio.subsonic +""" + +from .dbutils import * + +__version__ = '0.0.1' diff --git a/lib/dbutils/dbutils.py b/lib/dbutils/dbutils.py new file mode 100644 index 0000000..bb97c38 --- /dev/null +++ b/lib/dbutils/dbutils.py @@ -0,0 +1,80 @@ +import sqlite3 as sql + +tbl_artist_info_ddl = str('CREATE TABLE artist_info (' + 'artist_id TEXT NOT NULL PRIMARY KEY,' + 'artist_info TEXT,' + 'last_update TEXT);') + +class SQLiteDatabase(object): + def __init__(self, db_filename): + print("Init %s"%db_filename) + self.db_filename = db_filename + self.conn = None + + self.connect() + + def connect(self): + try: + #xbmc.log("Trying connection to the database %s"%self.db_filename, xbmc.LOGINFO) + print("Trying connection to the database %s"%self.db_filename) + self.conn = sql.connect(self.db_filename) + cursor = self.conn.cursor() + cursor.execute(str('SELECT SQLITE_VERSION()')) + #xbmc.log("Connection %s was successful %s"%(self.db_filename, cursor.fetchone()[0]), xbmc.LOGINFO) + print("Connection %s was successful %s"%(self.db_filename, cursor.fetchone()[0])) + cursor.row_factory = lambda cursor, row: row[0] + cursor.execute(str('SELECT name FROM sqlite_master WHERE type=\'table\' ''AND name NOT LIKE \'sqlite_%\'')) + list_tables = cursor.fetchall() + if not list_tables: + # If no tables exist create a new one + #xbmc.log("Creating Subsonic local DB", xbmc.LOGINFO) + print("Creating Subsonic local DB") + cursor.execute(tbl_artist_info_ddl) + except sql.Error as e: + #xbmc.log("SQLite error %s"%e.args[0], xbmc.LOGINFO) + print("SQLite error %s"%e.args[0]) + + def get_cursor(self): + return self.conn.cursor() + + def run_query(self, query, params=None, cursor=None): + print("Processing query %s params %s"%(str(query),str(params))) + try: + if cursor is None: + cursor = self.get_cursor() + if params is not None: + cursor.execute(query, params) + else: + cursor.execute(query) + return cursor + except sql.Error as e: + print("SQLite error %s"%e.args[0]) + except ValueError: + print("Error query %s"%str(query)) + print("Error query type %s"%type(query)) + print("Error params %s"%str(params)) + print("Error params type %s"%type(params)) + + def update_artist(self, artist_id, artist_info, update_time): + success = False + query = 'INSERT or REPLACE INTO artist_info VALUES (?, ?, ?)' + params = (str(artist_id), str(artist_info), str(update_time)) + cursor = self.run_query(query, params) + try: + self.conn.commit() + success = True + except Exception as e: + print("Exception %s"%e) + pass + return success + + def get_artist_info(self, artist_id): + query = 'SELECT * FROM artist_info WHERE artist_id = ?' + params = [str(artist_id)] + cursor = self.run_query(query, params) + return cursor.fetchall() + + def close(self): + if self.conn: + self.conn.close() + diff --git a/lib/libsonic/connection.py b/lib/libsonic/connection.py index 07ab583..e96679d 100644 --- a/lib/libsonic/connection.py +++ b/lib/libsonic/connection.py @@ -228,11 +228,13 @@ class Connection(object): """ methodName = 'ping' viewName = '%s.view' % methodName - + print("test") req = self._getRequest(viewName) - xbmc.log("Pinging %s"%str(req.full_url),xbmc.LOGDEBUG) + print("Pinging %s"%str(req.full_url))#,#xbmc.logDEBUG) + #xbmc.log("Pinging %s"%str(req.full_url),#xbmc.logDEBUG) try: res = self._doInfoReq(req) + print(res) except Exception as e: print("Ping failed %s"%e) return False @@ -896,11 +898,11 @@ class Connection(object): 'converted': converted}) req = self._getRequest(viewName, q) - #xbmc.log("Requesting %s"%str(req.full_url),xbmc.LOGDEBUG) + ##xbmc.log("Requesting %s"%str(req.full_url),#xbmc.logDEBUG) return_url = req.full_url if self._insecure: return_url += '|verifypeer=false' - xbmc.log("Request is insecure %s"%return_url,level=xbmc.LOGDEBUG) + #xbmc.log("Request is insecure %s"%return_url,level=#xbmc.logDEBUG) return return_url @@ -945,11 +947,11 @@ class Connection(object): q = self._getQueryDict({'id': aid, 'size': size}) req = self._getRequest(viewName, q) - #xbmc.log("Requesting %s"%str(req.full_url),xbmc.LOGDEBUG) + ##xbmc.log("Requesting %s"%str(req.full_url),#xbmc.logDEBUG) return_url = req.full_url if self._insecure: return_url += '|verifypeer=false' - xbmc.log("Request is insecure %s"%return_url,level=xbmc.LOGDEBUG) + #xbmc.log("Request is insecure %s"%return_url,level=#xbmc.logDEBUG) return return_url @@ -1997,7 +1999,7 @@ class Connection(object): q['musicFolderId'] = musicFolderId req = self._getRequest(viewName, q) - xbmc.log("Requesting %s"%str(req.full_url),xbmc.LOGDEBUG) + #xbmc.log("Requesting %s"%str(req.full_url),#xbmc.logDEBUG) res = self._doInfoReq(req) self._checkStatus(res) return res @@ -2809,12 +2811,13 @@ class Connection(object): qdict.update(query) url = '%s:%d/%s/%s' % (self._baseUrl, self._port, self._serverPath, viewName) - #xbmc.log("Standard URL %s"%url,level=xbmc.LOGDEBUG) - #xbmc.log("Qdict %s"%str(qdict),level=xbmc.LOGDEBUG) + #xbmc.log("Standard URL %s"%url,level=#xbmc.logDEBUG) + #xbmc.log("Qdict %s"%str(qdict),level=#xbmc.logDEBUG) req = urllib.request.Request(url, urlencode(qdict).encode('utf-8')) if(self._useGET or ('getCoverArt' in viewName) or ('stream' in viewName)): url += '?%s' % urlencode(qdict) - #xbmc.log("UseGET URL %s"%(url),xbmc.LOGDEBUG) + #xbmc.log("UseGET URL %s"%(url), xbmc.logDEBUG) + print(url) req = urllib.request.Request(url) return req diff --git a/main.py b/main.py index 6dcdda5..ed604c9 100644 --- a/main.py +++ b/main.py @@ -20,6 +20,8 @@ from collections import namedtuple sys.path.append(xbmcvfs.translatePath(os.path.join(xbmcaddon.Addon("plugin.audio.subsonic").getAddonInfo("path"), "lib"))) import libsonic +#from lib.dbutils import SQLiteDatabase +import lib.dbutils from simpleplugin import Plugin from simpleplugin import Addon @@ -27,9 +29,14 @@ from simpleplugin import Addon # Create plugin instance plugin = Plugin() +db = None connection = None + cachetime = int(Addon().get_setting('cachetime')) +db_filename = "subsonic_sqlite.db" +db_path = os.path.join(plugin.profile_dir, db_filename) + local_starred = set({}) ListContext = namedtuple('ListContext', ['listing', 'succeeded','update_listing', 'cache_to_disk','sort_methods', 'view_mode','content', 'category']) PlayContext = namedtuple('PlayContext', ['path', 'play_item', 'succeeded']) @@ -748,34 +755,35 @@ def get_entry_playlist(item,params): } def get_artist_info(artist_id, forced=False): - print("Updating artist info for id: %s"%(artist_id)) - popup("Updating artist info\nplease wait") - last_update = 0 + db = get_db() artist_info = {} - cache_file = 'ar-%s'%hashlib.md5(artist_id.encode('utf-8')).hexdigest() - with plugin.get_storage(cache_file) as storage: - try: - last_update = storage['updated'] - except KeyError as e: - plugin.log("Artist keyerror, is this a new cache file? %s"%cache_file) - if(time.time()-last_update>(random.randint(1,111)*360) or forced): - plugin.log("Artist cache expired, updating %s elapsed vs random %s forced %s"%(int(time.time()-last_update),(random.randint(1,111)*3600), forced)) - try: - artist_info = connection.getArtistInfo2(artist_id).get('artistInfo2') - storage['artist_info'] = artist_info - storage['updated']=time.time() - except AttributeError as e: - plugin.log("Attribute error, probably couldn't find any info") - else: - print("Cache ok for %s retrieving"%artist_id) - artist_info = storage['artist_info'] + print("Retreiving artist info for id: %s"%(artist_id)) + popup("Updating artist info\nplease wait") + try: + artist_record = db.get_artist_info(artist_id) + print("Outer %s"%len(artist_record)) + if(len(artist_record)==0): + print("Empty record, getting data for %s"%artist_id) + artist_info = json.dumps(connection.getArtistInfo2(artist_id).get('artistInfo2')) + print("Adding to DB artist info: %s"%artist_info) + if(db.update_artist(artist_id, artist_info, time.time())): + plugin.log("Success") + else: + plugin.log("Failed") + artist_record = db.get_artist_info(artist_id) + artist_info = json.loads(artist_record[0][1]) + last_update = artist_record[0][2] + plugin.log("Artist info: %s"%artist_info) + plugin.log("Last update: %s"%last_update) + except Exception as e: + print("Error get info from DB %s"%e) return artist_info def get_entry_artist(item,params): image = connection.getCoverArtUrl(item.get('coverArt')) - #artist_info = get_artist_info(item.get('id')) - #artist_bio = artist_info.get('biography') - #fanart = artist_info.get('largeImageUrl') + artist_info = get_artist_info(item.get('id')) + artist_bio = artist_info.get('biography') + fanart = artist_info.get('largeImageUrl') fanart = image return { 'label': get_starred_label(item.get('id'),item.get('name')), @@ -795,7 +803,7 @@ def get_entry_artist(item,params): #'title': "testtitle", #'album': "testalbum", #'comment': "testcomment" - #'title': artist_bio + 'title': artist_bio } } } @@ -1512,6 +1520,16 @@ def walk_tracks_starred(): except KeyError: yield from () +def get_db(): + global db_path + #global db + plugin.log("Getting DB %s"%db_path) + if 1:#try: + db = lib.dbutils.SQLiteDatabase(db_path) + #except Exception as e: + # plugin.log("Connecting to DB failed: %s"%e) + return db + # Start plugin from within Kodi. if __name__ == "__main__": # Map actions