Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

# -*- coding: utf-8 -*- 

# 

# 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 copy 

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.prev_filter_tree_keys = None 

        self.filter_tree_items = None 

 

        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, basestring): 

                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 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(filter_dict.keys(), 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.iteritems(): 

                if (not status[field] in values) and 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.keys()) 

        if hide_cat: 

            for cat in hide_cat: 

                tree_keys.remove(cat) 

 

        torrent_keys, plugin_keys = self.torrents.separate_keys(tree_keys, torrent_ids) 

        # Keys are the same, so use previous items 

        if self.prev_filter_tree_keys != tree_keys: 

            self.filter_tree_items = dict((field, self.tree_fields[field]()) for field in tree_keys) 

            self.prev_filter_tree_keys = tree_keys 

        items = copy.deepcopy(self.filter_tree_items) 

 

        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 = {} 

        for field in tree_keys: 

            sorted_items[field] = sorted(items[field].iteritems()) 

 

        if "state" in tree_keys: 

            sorted_items["state"].sort(self._sort_state_items) 

 

        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, id, filter_func, filter_value=None): 

        self.registered_filters[id] = filter_func 

 

    def deregister_filter(self, id): 

        del self.registered_filters[id] 

 

exit    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 state_items.items(): 

            if value != "All" and count == 0: 

                del state_items[value] 

 

    def _sort_state_items(self, x, y): 

        "" 

        if x[0] in STATE_SORT: 

            ix = STATE_SORT.index(x[0]) 

        else: 

            ix = 99 

        if y[0] in STATE_SORT: 

            iy = STATE_SORT.index(y[0]) 

        else: 

            iy = 99 

 

        return ix - iy