class History: date_format = '%Y%m%d%H%M%S' def __init__(self): self.db = DBConnection() def clear(self): """ Clear all the history """ self.db.action( 'DELETE ' 'FROM history ' 'WHERE 1 = 1' ) def get(self, limit=100, action=None): """ :param limit: The maximum number of elements to return :param action: The type of action to filter in the history. Either 'downloaded' or 'snatched'. Anything else or no value will return everything (up to ``limit``) :return: The last ``limit`` elements of type ``action`` in the history """ actions = History._get_actions(action) limit = History._get_limit(limit) common_sql = 'SELECT action, date, episode, provider, h.quality, resource, season, show_name, showid ' \ 'FROM history h, tv_shows s ' \ 'WHERE h.showid = s.indexer_id ' filter_sql = 'AND action in (' + ','.join(['?'] * len(actions)) + ') ' order_sql = 'ORDER BY date DESC ' if limit == 0: if len(actions) > 0: results = self.db.select(common_sql + filter_sql + order_sql, actions) else: results = self.db.select(common_sql + order_sql) else: if len(actions) > 0: results = self.db.select(common_sql + filter_sql + order_sql + 'LIMIT ?', actions + [limit]) else: results = self.db.select(common_sql + order_sql + 'LIMIT ?', [limit]) data = [] for result in results: data.append({ 'action': result['action'], 'date': result['date'], 'episode': result['episode'], 'provider': result['provider'], 'quality': result['quality'], 'resource': result['resource'], 'season': result['season'], 'show_id': result['showid'], 'show_name': result['show_name'] }) return data def trim(self): """ Remove all elements older than 30 days from the history """ self.db.action( 'DELETE ' 'FROM history ' 'WHERE date < ?', [(datetime.today() - timedelta(days=30)).strftime(History.date_format)] ) @staticmethod def _get_actions(action): action = action.lower() if isinstance(action, (str, unicode)) else '' if action == 'downloaded': return Quality.DOWNLOADED if action == 'snatched': return Quality.SNATCHED return [] @staticmethod def _get_limit(limit): limit = try_int(limit, 0) return max(limit, 0)
class History: date_format = '%Y%m%d%H%M%S' def __init__(self): self.db = DBConnection() def clear(self): """ Clear all the history """ self.db.action('DELETE ' 'FROM history ' 'WHERE 1 = 1') def get(self, limit=100, action=None): """ :param limit: The maximum number of elements to return :param action: The type of action to filter in the history. Either 'downloaded' or 'snatched'. Anything else or no value will return everything (up to ``limit``) :return: The last ``limit`` elements of type ``action`` in the history """ action = action.lower() if isinstance(action, str) else '' limit = int(limit) if action == 'downloaded': actions = Quality.DOWNLOADED elif action == 'snatched': actions = Quality.SNATCHED else: actions = [] common_sql = 'SELECT action, date, episode, provider, h.quality, resource, season, show_name, showid ' \ 'FROM history h, tv_shows s ' \ 'WHERE h.showid = s.indexer_id ' filter_sql = 'AND action in (' + ','.join(['?'] * len(actions)) + ') ' order_sql = 'ORDER BY date DESC ' if limit == 0: if len(actions) > 0: results = self.db.select(common_sql + filter_sql + order_sql, actions) else: results = self.db.select(common_sql + order_sql) else: if len(actions) > 0: results = self.db.select( common_sql + filter_sql + order_sql + 'LIMIT ?', actions + [limit]) else: results = self.db.select(common_sql + order_sql + 'LIMIT ?', [limit]) data = [] for result in results: data.append({ 'action': result['action'], 'date': result['date'], 'episode': result['episode'], 'provider': result['provider'], 'quality': result['quality'], 'resource': result['resource'], 'season': result['season'], 'show_id': result['showid'], 'show_name': result['show_name'] }) return data def trim(self): """ Remove all elements older than 30 days from the history """ self.db.action('DELETE ' 'FROM history ' 'WHERE date < ?', [(datetime.today() - timedelta(days=30)).strftime( History.date_format)])
class History: date_format = '%Y%m%d%H%M%S' def __init__(self): self.db = DBConnection() def clear(self): self.db.action( 'DELETE ' 'FROM history ' 'WHERE 1 = 1' ) def get(self, limit=100, action=None): action = action.lower() if isinstance(action, str) else '' limit = int(limit) if action == 'downloaded': actions = Quality.DOWNLOADED elif action == 'snatched': actions = Quality.SNATCHED else: actions = Quality.SNATCHED + Quality.DOWNLOADED if limit == 0: results = self.db.select( 'SELECT h.*, show_name ' 'FROM history h, tv_shows s ' 'WHERE h.showid = s.indexer_id ' 'AND action in (' + ','.join(['?'] * len(actions)) + ') ' 'ORDER BY date DESC', actions ) else: results = self.db.select( 'SELECT h.*, show_name ' 'FROM history h, tv_shows s ' 'WHERE h.showid = s.indexer_id ' 'AND action in (' + ','.join(['?'] * len(actions)) + ') ' 'ORDER BY date DESC ' 'LIMIT ?', actions + [limit] ) data = [] for result in results: data.append({ 'action': result['action'], 'date': result['date'], 'episode': result['episode'], 'provider': result['provider'], 'quality': result['quality'], 'resource': result['resource'], 'season': result['season'], 'show_id': result['showid'], 'show_name': result['show_name'] }) return data def trim(self): self.db.action( 'DELETE ' 'FROM history ' 'WHERE date < ?', [(datetime.today() - timedelta(days=30)).strftime(History.date_format)] )
class History(object): date_format = '%Y%m%d%H%M%S' def __init__(self): self.db = DBConnection() def remove(self, toRemove): """ Removes the selected history :param toRemove: Contains the properties of the log entries to remove """ query = '' for item in toRemove: query = query + ' OR ' if query != '' else '' query = query + '(date IN ({0}) AND showid = {1} ' \ 'AND season = {2} AND episode = {3})' \ .format(','.join(item['dates']), item['show_id'], \ item['season'], item['episode']) self.db.action('DELETE FROM history WHERE ' + query) def clear(self): """ Clear all the history """ self.db.action('DELETE ' 'FROM history ' 'WHERE 1 = 1') def get(self, limit=100, action=None): """ :param limit: The maximum number of elements to return :param action: The type of action to filter in the history. Either 'downloaded' or 'snatched'. Anything else or no value will return everything (up to ``limit``) :return: The last ``limit`` elements of type ``action`` in the history """ actions = History._get_actions(action) limit = History._get_limit(limit) common_sql = 'SELECT action, date, episode, provider, h.quality, resource, season, show_name, showid ' \ 'FROM history h, tv_shows s ' \ 'WHERE h.showid = s.indexer_id ' filter_sql = 'AND action in (' + ','.join(['?'] * len(actions)) + ') ' order_sql = 'ORDER BY date DESC ' if limit == 0: if actions: results = self.db.select(common_sql + filter_sql + order_sql, actions) else: results = self.db.select(common_sql + order_sql) else: if actions: results = self.db.select( common_sql + filter_sql + order_sql + 'LIMIT ?', actions + [limit]) else: results = self.db.select(common_sql + order_sql + 'LIMIT ?', [limit]) data = [] for result in results: data.append({ 'action': result[b'action'], 'date': result[b'date'], 'episode': result[b'episode'], 'provider': result[b'provider'], 'quality': result[b'quality'], 'resource': result[b'resource'], 'season': result[b'season'], 'show_id': result[b'showid'], 'show_name': result[b'show_name'] }) return data def trim(self): """ Remove all elements older than 30 days from the history """ self.db.action('DELETE ' 'FROM history ' 'WHERE date < ?', [(datetime.today() - timedelta(days=30)).strftime( History.date_format)]) @staticmethod def _get_actions(action): action = action.lower() if isinstance(action, six.string_types) else '' if action == 'downloaded': return Quality.DOWNLOADED if action == 'snatched': return Quality.SNATCHED return [] @staticmethod def _get_limit(limit): limit = try_int(limit, 0) return max(limit, 0)
class History(object): date_format = '%Y%m%d%H%M%S' def __init__(self): self.db = DBConnection() def clear(self): """ Clear all the history """ self.db.action( 'DELETE ' 'FROM history ' 'WHERE 1 = 1' ) def get(self, limit=100, action=None): """ :param limit: The maximum number of elements to return :param action: The type of action to filter in the history. Either 'downloaded' or 'snatched'. Anything else or no value will return everything (up to ``limit``) :return: The last ``limit`` elements of type ``action`` in the history """ # TODO: Make this a generator instead # TODO: Split compact and detailed into separate methods # TODO: Add a date limit as well # TODO: Clean up history.mako actions = History._get_actions(action) limit = max(try_int(limit), 0) common_sql = 'SELECT show_name, showid, season, episode, h.quality, ' \ 'action, provider, resource, date ' \ 'FROM history h, tv_shows s ' \ 'WHERE h.showid = s.indexer_id ' filter_sql = 'AND action in (' + ','.join(['?'] * len(actions)) + ') ' order_sql = 'ORDER BY date DESC ' if actions: sql_results = self.db.select(common_sql + filter_sql + order_sql, actions) else: sql_results = self.db.select(common_sql + order_sql) detailed = [] compact = dict() # TODO: Convert to a defaultdict and compact items as needed # TODO: Convert to using operators to combine items for row in sql_results: row = History.Item(*row) if row.index in compact: compact[row.index].actions.append(row.cur_action) elif not limit or len(compact) < limit: detailed.append(row) compact[row.index] = row.compacted() results = namedtuple('results', ['detailed', 'compact']) return results(detailed, compact.values()) def trim(self, days=30): """ Remove expired elements from history :param days: number of days to keep """ date = datetime.today() - timedelta(days) self.db.action( 'DELETE ' 'FROM history ' 'WHERE date < ?', [date.strftime(History.date_format)] ) @staticmethod def _get_actions(action): action = action.lower() if isinstance(action, (str, unicode)) else '' result = None if action == 'downloaded': result = Quality.DOWNLOADED elif action == 'snatched': result = Quality.SNATCHED return result or [] action_fields = ('action', 'provider', 'resource', 'date', ) # A specific action from history Action = namedtuple('Action', action_fields) Action.width = len(action_fields) index_fields = ('show_id', 'season', 'episode', 'quality', ) # An index for an item or compact item from history Index = namedtuple('Index', index_fields) Index.width = len(index_fields) compact_fields = ('show_name', 'index', 'actions', ) # Related items compacted with a list of actions from history CompactItem = namedtuple('CompactItem', compact_fields) item_fields = tuple( # make it a tuple so its immutable ['show_name'] + list(index_fields) + list(action_fields) ) class Item(namedtuple('Item', item_fields)): # TODO: Allow items to be added to a compact item """ An individual row item from history """ # prevent creation of a __dict__ when subclassing # from a class that uses __slots__ __slots__ = () @property def index(self): """ Create a look-up index for the item """ return History.Index( self.show_id, self.season, self.episode, self.quality, ) @property def cur_action(self): """ Create the current action from action_fields """ return History.Action( self.action, self.provider, self.resource, self.date, ) def compacted(self): """ Create a CompactItem :returns: the current item in compact form """ result = History.CompactItem( self.show_name, self.index, [self.cur_action], # actions ) return result def __add__(self, other): """ Combines two history items with the same index :param other: The other item to add :returns: a compact item with elements from both items :raises AssertionError: if indexes do not match """ # Index comparison and validation is done by _radd_ return self.compacted() + other def __radd__(self, other): """ Adds a history item to a compact item :param other: The compact item to append :returns: the updated compact item :raises AssertionError: if indexes do not match """ if self.index == other.index: other.actions.append(self.cur_action) return other else: raise AssertionError('cannot add items with different indexes')