summaryrefslogtreecommitdiffstats
path: root/deluge/core/filtermanager.py
diff options
context:
space:
mode:
Diffstat (limited to 'deluge/core/filtermanager.py')
-rw-r--r--deluge/core/filtermanager.py274
1 files changed, 274 insertions, 0 deletions
diff --git a/deluge/core/filtermanager.py b/deluge/core/filtermanager.py
new file mode 100644
index 0000000..a60cc5b
--- /dev/null
+++ b/deluge/core/filtermanager.py
@@ -0,0 +1,274 @@
+#
+# Copyright (C) 2008 Martijn Voncken <mvoncken@gmail.com>
+#
+# This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with
+# the additional special exception to link portions of this program with the OpenSSL library.
+# See LICENSE for more details.
+#
+
+import logging
+
+import deluge.component as component
+from deluge.common import TORRENT_STATE
+
+log = logging.getLogger(__name__)
+
+STATE_SORT = ['All', 'Active'] + TORRENT_STATE
+
+
+# Special purpose filters:
+def filter_keywords(torrent_ids, values):
+ # Cleanup
+ keywords = ','.join([v.lower() for v in values])
+ keywords = keywords.split(',')
+
+ for keyword in keywords:
+ torrent_ids = filter_one_keyword(torrent_ids, keyword)
+ return torrent_ids
+
+
+def filter_one_keyword(torrent_ids, keyword):
+ """
+ search torrent on keyword.
+ searches title,state,tracker-status,tracker,files
+ """
+ all_torrents = component.get('TorrentManager').torrents
+
+ for torrent_id in torrent_ids:
+ torrent = all_torrents[torrent_id]
+ if keyword in torrent.filename.lower():
+ yield torrent_id
+ elif keyword in torrent.state.lower():
+ yield torrent_id
+ elif torrent.trackers and keyword in torrent.trackers[0]['url']:
+ yield torrent_id
+ elif keyword in torrent_id:
+ yield torrent_id
+ # Want to find broken torrents (search on "error", or "unregistered")
+ elif keyword in torrent.tracker_status.lower():
+ yield torrent_id
+ else:
+ for t_file in torrent.get_files():
+ if keyword in t_file['path'].lower():
+ yield torrent_id
+ break
+
+
+def filter_by_name(torrent_ids, search_string):
+ all_torrents = component.get('TorrentManager').torrents
+ try:
+ search_string, match_case = search_string[0].split('::match')
+ except ValueError:
+ search_string = search_string[0]
+ match_case = False
+
+ if match_case is False:
+ search_string = search_string.lower()
+
+ for torrent_id in torrent_ids:
+ torrent_name = all_torrents[torrent_id].get_name()
+ if match_case is False:
+ torrent_name = all_torrents[torrent_id].get_name().lower()
+ else:
+ torrent_name = all_torrents[torrent_id].get_name()
+
+ if search_string in torrent_name:
+ yield torrent_id
+
+
+def tracker_error_filter(torrent_ids, values):
+ filtered_torrent_ids = []
+ tm = component.get('TorrentManager')
+
+ # If this is a tracker_host, then we need to filter on it
+ if values[0] != 'Error':
+ for torrent_id in torrent_ids:
+ if values[0] == tm[torrent_id].get_status(['tracker_host'])['tracker_host']:
+ filtered_torrent_ids.append(torrent_id)
+ return filtered_torrent_ids
+
+ # Check torrent's tracker_status for 'Error:' and return those torrent_ids
+ for torrent_id in torrent_ids:
+ if 'Error:' in tm[torrent_id].get_status(['tracker_status'])['tracker_status']:
+ filtered_torrent_ids.append(torrent_id)
+ return filtered_torrent_ids
+
+
+class FilterManager(component.Component):
+ """FilterManager"""
+
+ def __init__(self, core):
+ component.Component.__init__(self, 'FilterManager')
+ log.debug('FilterManager init..')
+ self.core = core
+ self.torrents = core.torrentmanager
+ self.registered_filters = {}
+ self.register_filter('keyword', filter_keywords)
+ self.register_filter('name', filter_by_name)
+ self.tree_fields = {}
+
+ self.register_tree_field('state', self._init_state_tree)
+
+ def _init_tracker_tree():
+ return {'Error': 0}
+
+ self.register_tree_field('tracker_host', _init_tracker_tree)
+
+ self.register_filter('tracker_host', tracker_error_filter)
+
+ def _init_users_tree():
+ return {'': 0}
+
+ self.register_tree_field('owner', _init_users_tree)
+
+ def filter_torrent_ids(self, filter_dict):
+ """
+ returns a list of torrent_id's matching filter_dict.
+ core filter method
+ """
+ if not filter_dict:
+ return self.torrents.get_torrent_list()
+
+ # Sanitize input: filter-value must be a list of strings
+ for key, value in filter_dict.items():
+ if isinstance(value, str):
+ filter_dict[key] = [value]
+
+ # Optimized filter for id
+ if 'id' in filter_dict:
+ torrent_ids = list(filter_dict['id'])
+ del filter_dict['id']
+ else:
+ torrent_ids = self.torrents.get_torrent_list()
+
+ # Return if there's nothing more to filter
+ if not filter_dict:
+ return torrent_ids
+
+ # Special purpose, state=Active.
+ if 'state' in filter_dict:
+ # We need to make sure this is a list for the logic below
+ filter_dict['state'] = list(filter_dict['state'])
+
+ if 'state' in filter_dict and 'Active' in filter_dict['state']:
+ filter_dict['state'].remove('Active')
+ if not filter_dict['state']:
+ del filter_dict['state']
+ torrent_ids = self.filter_state_active(torrent_ids)
+
+ if not filter_dict:
+ return torrent_ids
+
+ # Registered filters
+ for field, values in list(filter_dict.items()):
+ if field in self.registered_filters:
+ # Filters out doubles
+ torrent_ids = list(
+ set(self.registered_filters[field](torrent_ids, values))
+ )
+ del filter_dict[field]
+
+ if not filter_dict:
+ return torrent_ids
+
+ torrent_keys, plugin_keys = self.torrents.separate_keys(
+ list(filter_dict), torrent_ids
+ )
+ # Leftover filter arguments, default filter on status fields.
+ for torrent_id in list(torrent_ids):
+ status = self.core.create_torrent_status(
+ torrent_id, torrent_keys, plugin_keys
+ )
+ for field, values in filter_dict.items():
+ if field in status and status[field] in values:
+ continue
+ elif torrent_id in torrent_ids:
+ torrent_ids.remove(torrent_id)
+ return torrent_ids
+
+ def get_filter_tree(self, show_zero_hits=True, hide_cat=None):
+ """
+ returns {field: [(value,count)] }
+ for use in sidebar.
+ """
+ torrent_ids = self.torrents.get_torrent_list()
+ tree_keys = list(self.tree_fields)
+ if hide_cat:
+ for cat in hide_cat:
+ tree_keys.remove(cat)
+
+ torrent_keys, plugin_keys = self.torrents.separate_keys(tree_keys, torrent_ids)
+ items = {field: self.tree_fields[field]() for field in tree_keys}
+
+ for torrent_id in list(torrent_ids):
+ status = self.core.create_torrent_status(
+ torrent_id, torrent_keys, plugin_keys
+ ) # status={key:value}
+ for field in tree_keys:
+ value = status[field]
+ items[field][value] = items[field].get(value, 0) + 1
+
+ if 'tracker_host' in items:
+ items['tracker_host']['All'] = len(torrent_ids)
+ items['tracker_host']['Error'] = len(
+ tracker_error_filter(torrent_ids, ('Error',))
+ )
+
+ if not show_zero_hits:
+ for cat in ['state', 'owner', 'tracker_host']:
+ if cat in tree_keys:
+ self._hide_state_items(items[cat])
+
+ # Return a dict of tuples:
+ sorted_items = {field: sorted(items[field].items()) for field in tree_keys}
+
+ if 'state' in tree_keys:
+ sorted_items['state'].sort(key=self._sort_state_item)
+
+ return sorted_items
+
+ def _init_state_tree(self):
+ init_state = {}
+ init_state['All'] = len(self.torrents.get_torrent_list())
+ for state in TORRENT_STATE:
+ init_state[state] = 0
+ init_state['Active'] = len(
+ self.filter_state_active(self.torrents.get_torrent_list())
+ )
+ return init_state
+
+ def register_filter(self, filter_id, filter_func, filter_value=None):
+ self.registered_filters[filter_id] = filter_func
+
+ def deregister_filter(self, filter_id):
+ del self.registered_filters[filter_id]
+
+ def register_tree_field(self, field, init_func=lambda: {}):
+ self.tree_fields[field] = init_func
+
+ def deregister_tree_field(self, field):
+ if field in self.tree_fields:
+ del self.tree_fields[field]
+
+ def filter_state_active(self, torrent_ids):
+ for torrent_id in list(torrent_ids):
+ status = self.torrents[torrent_id].get_status(
+ ['download_payload_rate', 'upload_payload_rate']
+ )
+ if status['download_payload_rate'] or status['upload_payload_rate']:
+ pass
+ else:
+ torrent_ids.remove(torrent_id)
+ return torrent_ids
+
+ def _hide_state_items(self, state_items):
+ """For hide(show)-zero hits"""
+ for value, count in list(state_items.items()):
+ if value != 'All' and count == 0:
+ del state_items[value]
+
+ def _sort_state_item(self, item):
+ try:
+ return STATE_SORT.index(item[0])
+ except ValueError:
+ return 99