From 08b7a82896322dfe91d5e2122822939a0d9ed87d Mon Sep 17 00:00:00 2001 From: Patrick Klein Date: Sun, 22 Apr 2018 11:12:35 -0700 Subject: [PATCH] add **kwargs to dbh methods --- resources/lib/database_handler.py | 105 +++++++++++++++--------------- resources/lib/managed.py | 12 ++-- resources/lib/staged.py | 17 +++-- resources/lib/synced.py | 7 +- 4 files changed, 76 insertions(+), 65 deletions(-) diff --git a/resources/lib/database_handler.py b/resources/lib/database_handler.py index d98e2d3..0e7b127 100644 --- a/resources/lib/database_handler.py +++ b/resources/lib/database_handler.py @@ -45,23 +45,40 @@ def __del__(self): self.db.close() @log_decorator - def get_content_items(self, status, mediatype=None): - ''' Queries Content table for sorted items with status and mediatype (optional) - and casts results as ContentItem subclass ''' - # query database, add Mediatype constraint if parameter is provided - if mediatype: - self.c.execute( - "SELECT * FROM Content WHERE Status=? AND Mediatype=? \ - ORDER BY (CASE WHEN Title LIKE 'the %' THEN substr(Title,5) \ - ELSE Title END) COLLATE NOCASE", - (status, mediatype)) - else: - self.c.execute( - "SELECT * FROM Content WHERE Status=? \ - ORDER BY (CASE WHEN Title LIKE 'the %' THEN substr(Title,5) \ - ELSE Title END) COLLATE NOCASE", - (status,)) - # get results and return items as objects + def get_content_items(self, **kwargs): + ''' Queries Content table for sorted items with given constaints + and casts results as ContentItem subclass + + keyword arguments: + mediatype = string, 'movie' or 'tvshow' + status = string, 'managed' or 'staged' + show_title = string, any show title + order= string, any single column + ''' + # define template for this sql command + sql_templ = "SELECT * FROM Content{c}{o}" + # define constraint and/or order string usings kwargs + c_list = [] + o = '' + params = tuple() + for k, v in kwargs.iteritems(): + if k == 'status': + c_list.append('Status=?') + params += (v,) + elif k == 'mediatype': + c_list.append('Mediatype=?') + params += (v,) + elif k == 'show_title': + c_list.append('Show_Title=?') + params += (v,) + elif k == 'order': + o = " ORDER BY (CASE WHEN {0} LIKE 'the %' THEN substr({0},5) \ + ELSE {0} END) COLLATE NOCASE".format(v) + c = ' WHERE ' + ' AND '.join(c_list) if c_list else '' + # format and execute sql command + sql_comm = sql_templ.format(c=c, o=o) + self.c.execute(sql_comm, params) + # get results and return items as content items rows = self.c.fetchall() return [self.content_item_from_db(x) for x in rows] @@ -79,20 +96,6 @@ def get_all_shows(self, status): rows = self.c.fetchall() return [x[0] for x in rows if x[0] is not None] - @log_decorator - def get_show_episodes(self, status, show_title): - ''' Queries Content table for tvshow items with show_title - and casts results as EpisodeItem ''' - # query database - self.c.execute( - "SELECT * FROM Content WHERE Status=? AND Show_Title=?\ - ORDER BY (CASE WHEN Title LIKE 'the %' THEN substr(Title,5) \ - ELSE Title END) COLLATE NOCASE", - (status, show_title)) - # get results and return items as objects - rows = self.c.fetchall() - return [self.content_item_from_db(x) for x in rows] - @utf8_decorator @log_decorator def load_item(self, path): @@ -112,15 +115,13 @@ def path_exists(self, path, status=None): #TODO: consider adding mediatype as optional parameter # might speed-up by adding additional constraint #TODO: test speed against a set from "get_content_paths" - # query database, add Status constraint if parameter is provided + # build sql command and parameters, adding status if provided + sql_comm = 'SELECT (Directory) FROM Content WHERE Directory=?' + params = (path,) if status: - self.c.execute( - 'SELECT (Directory) FROM Content WHERE Directory=? AND Status=?', - (path, status)) - else: - self.c.execute( - 'SELECT (Directory) FROM Content WHERE Directory=?', - (path,)) + sql_comm += 'AND Status=?' + params += (status,) + self.c.execute(sql_comm, params) # get result and return True if result is found res = self.c.fetchone() return bool(res) @@ -129,19 +130,19 @@ def path_exists(self, path, status=None): @log_decorator def add_content_item(self, path, title, mediatype, show_title=None): ''' Adds item to Content with given parameters ''' - # log and insert row according to mediatype - if mediatype == 'movie': - self.c.execute( - "INSERT OR IGNORE INTO Content \ - (Directory, Title, Mediatype, Status, Show_Title) \ - VALUES (?, ?, ?, 'staged', NULL)", - (path, title, mediatype)) - elif mediatype == 'tvshow': - self.c.execute( - "INSERT OR IGNORE INTO Content \ - (Directory, Title, Mediatype, Status, Show_Title) \ - VALUES (?, ?, ?, 'staged', ?)", - (path, title, mediatype, show_title)) + # define sql command string + sql_comm = "INSERT OR IGNORE INTO Content \ + (Directory, Title, Mediatype, Status, Show_Title) \ + VALUES (?, ?, ?, 'staged', {0})" + params = (path, title, mediatype) + # format comamnd & params depending on movie or tvshow + if mediatype == 'tvshow': + sql_comm = sql_comm.format('?') + params += (show_title,) + else: + sql_comm = sql_comm.format('NULL') + # execute and commit sql command + self.c.execute(sql_comm, params) self.db.commit() @utf8_decorator diff --git a/resources/lib/managed.py b/resources/lib/managed.py index 15c6ba1..f260cc2 100644 --- a/resources/lib/managed.py +++ b/resources/lib/managed.py @@ -38,7 +38,8 @@ def view_all(self): STR_MOVE_ALL_BACK_TO_STAGED = self.addon.getLocalizedString(32010) STR_BACK = self.addon.getLocalizedString(32011) STR_MANAGED_MOVIES = self.addon.getLocalizedString(32012) - managed_movies = self.dbh.get_content_items(status='managed', mediatype='movie') + managed_movies = self.dbh.get_content_items(status='managed', mediatype='movie', + order='Title') if not managed_movies: xbmcgui.Dialog().ok(self.STR_ADDON_NAME, STR_NO_MANAGED_MOVIES) return self.mainmenu.view() @@ -167,7 +168,8 @@ def remove_all(self): STR_ALL_TV_SHOWS_REMOVED = self.addon.getLocalizedString(32025) pDialog = xbmcgui.DialogProgress() pDialog.create(self.STR_ADDON_NAME, STR_REMOVING_ALL_TV_SHOWS) - managed_tv_items = self.dbh.get_content_items(status='managed', mediatype='tvshow') + managed_tv_items = self.dbh.get_content_items(status='managed', mediatype='tvshow', + order='Show_Title') for item in managed_tv_items: pDialog.update(0, line2=item.get_show_title(), line3=item.get_title()) item.remove_from_library() @@ -182,7 +184,8 @@ def move_all_to_staged(self): STR_ALL_TV_SHOWS_MOVED_TO_STAGED = self.addon.getLocalizedString(32027) pDialog = xbmcgui.DialogProgress() pDialog.create(self.STR_ADDON_NAME, STR_MOVING_ALL_TV_SHOWS_BACK_TO_STAGED) - managed_tv_items = self.dbh.get_content_items(status='managed', mediatype='tvshow') + managed_tv_items = self.dbh.get_content_items(status='managed', mediatype='tvshow', + order='Show_Title') for item in managed_tv_items: pDialog.update(0, line2=item.get_show_title(), line3=item.get_title()) item.remove_from_library() @@ -202,7 +205,8 @@ def view_episodes(self, show_title): STR_MOVE_ALL_EPISODES_BACK_TO_STAGED = self.addon.getLocalizedString(32030) STR_BACK = self.addon.getLocalizedString(32011) STR_MANAGED_x_EPISODES = self.addon.getLocalizedString(32031) % show_title - managed_episodes = self.dbh.get_show_episodes('managed', show_title) + managed_episodes = self.dbh.get_content_items(status='managed', show_title=show_title, + order='Title') if not managed_episodes: xbmcgui.Dialog().ok(self.STR_ADDON_NAME, STR_NO_MANAGED_x_EPISODES) return self.view_shows() diff --git a/resources/lib/staged.py b/resources/lib/staged.py index 799594f..1ef1874 100644 --- a/resources/lib/staged.py +++ b/resources/lib/staged.py @@ -50,7 +50,8 @@ def view_all(self): STR_GENERATE_ALL_METADATA_ITEMS = self.addon.getLocalizedString(32040) STR_BACK = self.addon.getLocalizedString(32011) STR_STAGED_MOVIES = self.addon.getLocalizedString(32041) - staged_movies = self.dbh.get_content_items(status='staged', mediatype='movie') + staged_movies = self.dbh.get_content_items(status='staged', mediatype='movie', + order='Title') if not staged_movies: xbmcgui.Dialog().ok(self.STR_ADDON_NAME, STR_NO_STAGED_MOVIES) return self.mainmenu.view() @@ -175,7 +176,7 @@ def options(self, item): @staticmethod def rename_dialog(item): ''' prompts input for new name, and renames if non-empty string ''' - #TODO: move to utils so it's not duplicated + #TODO: move to utils or parent class so it's not duplicated input_ret = xbmcgui.Dialog().input("Title", defaultt=item.title) if input_ret: item.rename(input_ret) @@ -242,7 +243,8 @@ def add_all_shows(self): STR_ALL_TV_SHOWS_ADDED = self.addon.getLocalizedString(32060) pDialog = xbmcgui.DialogProgress() pDialog.create(self.STR_ADDON_NAME, STR_ADDING_ALL_TV_SHOWS) - staged_tv_items = self.dbh.get_content_items(status='staged', mediatype='tvshow') + staged_tv_items = self.dbh.get_content_items(status='staged', mediatype='tvshow', + order='Show_Title') for item in staged_tv_items: pDialog.update(0, line2=item.get_title()) item.add_to_library() @@ -256,7 +258,8 @@ def add_all_with_metadata(self): STR_ALL_TV_SHOW_ITEMS_WITH_METADATA_ADDED = self.addon.getLocalizedString(32062) pDialog = xbmcgui.DialogProgress() pDialog.create(self.STR_ADDON_NAME, STR_ADDING_ALL_TV_SHOW_ITEMS_WITH_METADATA) - staged_tv_items = self.dbh.get_content_items(status='staged', mediatype='tvshow') + staged_tv_items = self.dbh.get_content_items(status='staged', mediatype='tvshow', + order='Show_Title') for item in staged_tv_items: safe_title = clean_name(item.get_title()) safe_showtitle = clean_name(item.get_show_title()) @@ -287,7 +290,8 @@ def generate_all_metadata(self): STR_ALL_TV_SHOW_METADATA_CREATED = self.addon.getLocalizedString(32064) pDialog = xbmcgui.DialogProgress() pDialog.create(self.STR_ADDON_NAME, STR_GENERATING_ALL_TV_SHOW_METADATA) - staged_tv_items = self.dbh.get_content_items(status='staged', mediatype='tvshow') + staged_tv_items = self.dbh.get_content_items(status='staged', mediatype='tvshow', + order='Show_Title') for item in staged_tv_items: pDialog.update(0, line2=item.get_show_title(), line3=item.get_title()) item.create_metadata_item() @@ -310,7 +314,8 @@ def view_episodes(self, show_title): STR_GENERATE_ALL_METADATA_ITEMS = self.addon.getLocalizedString(32040) STR_BACK = self.addon.getLocalizedString(32011) STR_STAGED_x_EPISODES = self.addon.getLocalizedString(32070) % show_title - staged_episodes = self.dbh.get_show_episodes('staged', show_title) + staged_episodes = self.dbh.get_content_items(status='staged', show_title=show_title, + order='Title') if not staged_episodes: xbmcgui.Dialog().ok(self.STR_ADDON_NAME, STR_NO_STAGED_x_EPISODES) return self.view_shows() diff --git a/resources/lib/synced.py b/resources/lib/synced.py index 04730cd..0427441 100644 --- a/resources/lib/synced.py +++ b/resources/lib/synced.py @@ -19,6 +19,7 @@ class Synced(object): provides windows for displaying synced directories, and tools for managing them and updating their contents ''' + #IDEA: new "find all directories" context item that finds and consolidates directories def __init__(self, mainmenu): self.addon = xbmcaddon.Addon() @@ -115,9 +116,9 @@ def update_all(self): #TODO: wait until after confirmation to remove staged items also #TODO: bugfix: single-movies won't actually get removed if they become unavailable # maybe load parent dir and check for path or label? it would be slower though - #TODO: bugfix: unicode error when comparing some blocked titles #TODO: option to only update specified or managed items #TODO: option to add update frequencies for specific directories (i.e. weekly/monthly/etc.) + #TODO: better error handling when plugins dont load during update (make it similar to clean) STR_GETTING_ALL_ITEMS_FROM_SYNCED_DIRS = self.addon.getLocalizedString(32089) STR_FINDING_ITEMS_TO_REMOVE_FROM_MANAGED = self.addon.getLocalizedString(32090) STR_REMOVING_ITEMS_FROM_STAGED = self.addon.getLocalizedString(32091) @@ -209,7 +210,7 @@ def update_all(self): # find managed paths not in dir_items, and prepare to remove pDialog.update(0, line1=STR_FINDING_ITEMS_TO_REMOVE_FROM_MANAGED) - managed_items = self.dbh.get_content_items('managed') + managed_items = self.dbh.get_content_items(status='managed') dir_paths = [x['file'] for x in dir_items] paths_to_remove = [] for item in managed_items: @@ -220,7 +221,7 @@ def update_all(self): # remove them from staged also (can do that immediately) pDialog.update(0, line1=STR_REMOVING_ITEMS_FROM_STAGED) - staged_items = self.dbh.get_content_items('staged') + staged_items = self.dbh.get_content_items(status='staged') for item in staged_items: if item.get_path() not in dir_paths: pDialog.update(0, line2=item.get_title())