瀏覽代碼

Merge remote-tracking branch 'upstream/master'

dalf 10 年之前
父節點
當前提交
829c758970
共有 5 個文件被更改,包括 182 次插入64 次删除
  1. 16
    4
      searx/engines/__init__.py
  2. 127
    0
      searx/query.py
  3. 10
    55
      searx/search.py
  4. 2
    2
      searx/translations/fr/LC_MESSAGES/messages.po
  5. 27
    3
      searx/webapp.py

+ 16
- 4
searx/engines/__init__.py 查看文件

@@ -142,16 +142,28 @@ def get_engines_stats():
142 142
         })
143 143
 
144 144
     for engine in pageloads:
145
-        engine['percentage'] = int(engine['avg'] / max_pageload * 100)
145
+        if max_pageload:
146
+            engine['percentage'] = int(engine['avg'] / max_pageload * 100)
147
+        else:
148
+            engine['percentage'] = 0
146 149
 
147 150
     for engine in results:
148
-        engine['percentage'] = int(engine['avg'] / max_results * 100)
151
+        if max_results:
152
+            engine['percentage'] = int(engine['avg'] / max_results * 100)
153
+        else:
154
+            engine['percentage'] = 0
149 155
 
150 156
     for engine in scores:
151
-        engine['percentage'] = int(engine['avg'] / max_score * 100)
157
+        if max_score:
158
+            engine['percentage'] = int(engine['avg'] / max_score * 100)
159
+        else:
160
+            engine['percentage'] = 0
152 161
 
153 162
     for engine in scores_per_result:
154
-        engine['percentage'] = int(engine['avg'] / max_score_per_result * 100)
163
+        if max_score_per_result:
164
+            engine['percentage'] = int(engine['avg'] / max_score_per_result * 100)
165
+        else:
166
+            engine['percentage'] = 0
155 167
 
156 168
     for engine in errors:
157 169
         if max_errors:

+ 127
- 0
searx/query.py 查看文件

@@ -0,0 +1,127 @@
1
+#!/usr/bin/env python
2
+
3
+'''
4
+searx is free software: you can redistribute it and/or modify
5
+it under the terms of the GNU Affero General Public License as published by
6
+the Free Software Foundation, either version 3 of the License, or
7
+(at your option) any later version.
8
+
9
+searx is distributed in the hope that it will be useful,
10
+but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
+GNU Affero General Public License for more details.
13
+
14
+You should have received a copy of the GNU Affero General Public License
15
+along with searx. If not, see < http://www.gnu.org/licenses/ >.
16
+
17
+(C) 2014 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>
18
+'''
19
+
20
+from searx.languages import language_codes
21
+from searx.engines import (
22
+    categories, engines, engine_shortcuts
23
+)
24
+import string
25
+import re
26
+
27
+
28
+class Query(object):
29
+    """parse query"""
30
+
31
+    def __init__(self, query, blocked_engines):
32
+        self.query = query
33
+        self.blocked_engines = []
34
+        
35
+        if blocked_engines:
36
+            self.blocked_engines = blocked_engines
37
+            
38
+        self.query_parts = []
39
+        self.engines = []
40
+        self.languages = []
41
+    
42
+    # parse query, if tags are set, which change the serch engine or search-language
43
+    def parse_query(self):
44
+        self.query_parts = []
45
+        
46
+        # split query, including whitespaces
47
+        raw_query_parts = re.split(r'(\s+)', self.query)
48
+        
49
+        parse_next = True
50
+        
51
+        for query_part in raw_query_parts:
52
+            if not parse_next:
53
+                self.query_parts[-1] += query_part
54
+                continue
55
+           
56
+            parse_next = False
57
+           
58
+            # part does only contain spaces, skip
59
+            if query_part.isspace()\
60
+               or query_part == '':
61
+                parse_next = True
62
+                self.query_parts.append(query_part)
63
+                continue
64
+
65
+            # this force a language            
66
+            if query_part[0] == ':':
67
+                lang = query_part[1:].lower()
68
+
69
+                # check if any language-code is equal with declared language-codes
70
+                for lc in language_codes:
71
+                    lang_id, lang_name, country = map(str.lower, lc)
72
+
73
+                    # if correct language-code is found, set it as new search-language
74
+                    if lang == lang_id\
75
+                       or lang_id.startswith(lang)\
76
+                       or lang == lang_name\
77
+                       or lang == country:
78
+                        parse_next = True
79
+                        self.languages.append(lang)
80
+                        break
81
+
82
+            # this force a engine or category
83
+            if query_part[0] == '!':
84
+                prefix = query_part[1:].replace('_', ' ')
85
+
86
+                # check if prefix is equal with engine shortcut
87
+                if prefix in engine_shortcuts\
88
+                   and not engine_shortcuts[prefix] in self.blocked_engines:
89
+                    parse_next = True
90
+                    self.engines.append({'category': 'none',
91
+                                         'name': engine_shortcuts[prefix]})
92
+                
93
+                # check if prefix is equal with engine name
94
+                elif prefix in engines\
95
+                        and not prefix in self.blocked_engines:
96
+                    parse_next = True
97
+                    self.engines.append({'category': 'none',
98
+                                        'name': prefix})
99
+
100
+                # check if prefix is equal with categorie name
101
+                elif prefix in categories:
102
+                    # using all engines for that search, which are declared under that categorie name
103
+                    parse_next = True
104
+                    self.engines.extend({'category': prefix,
105
+                                        'name': engine.name}
106
+                                        for engine in categories[prefix]
107
+                                        if not engine in self.blocked_engines)
108
+          
109
+            # append query part to query_part list
110
+            self.query_parts.append(query_part)
111
+
112
+    def changeSearchQuery(self, search_query):
113
+        if len(self.query_parts):
114
+            self.query_parts[-1] = search_query
115
+        else:
116
+            self.query_parts.append(search_query)
117
+            
118
+    def getSearchQuery(self):
119
+        if len(self.query_parts):
120
+            return self.query_parts[-1]
121
+        else:
122
+            return ''
123
+    
124
+    def getFullQuery(self):
125
+        # get full querry including whitespaces
126
+        return string.join(self.query_parts, '')
127
+

+ 10
- 55
searx/search.py 查看文件

@@ -26,6 +26,7 @@ from searx.engines import (
26 26
 )
27 27
 from searx.languages import language_codes
28 28
 from searx.utils import gen_useragent
29
+from searx.query import Query
29 30
 
30 31
 
31 32
 number_of_searches = 0
@@ -321,7 +322,15 @@ class Search(object):
321 322
         self.pageno = int(pageno_param)
322 323
 
323 324
         # parse query, if tags are set, which change the serch engine or search-language
324
-        self.parse_query()
325
+        query_obj = Query(self.query, self.blocked_engines)
326
+        query_obj.parse_query()        
327
+
328
+        # get last selected language in query, if possible
329
+        # TODO support search with multible languages
330
+        if len(query_obj.languages):
331
+            self.lang = query_obj.languages[-1]
332
+
333
+        self.engines = query_obj.engines
325 334
 
326 335
         self.categories = []
327 336
 
@@ -362,60 +371,6 @@ class Search(object):
362 371
                                     for x in categories[categ]
363 372
                                     if not x.name in self.blocked_engines)
364 373
 
365
-    # parse query, if tags are set, which change the serch engine or search-language
366
-    def parse_query(self):
367
-        query_parts = self.query.split()
368
-        modified = False
369
-
370
-        # check if language-prefix is set
371
-        if query_parts[0].startswith(':'):
372
-            lang = query_parts[0][1:].lower()
373
-
374
-            # check if any language-code is equal with declared language-codes
375
-            for lc in language_codes:
376
-                lang_id, lang_name, country = map(str.lower, lc)
377
-
378
-                # if correct language-code is found, set it as new search-language
379
-                if lang == lang_id\
380
-                   or lang_id.startswith(lang)\
381
-                   or lang == lang_name\
382
-                   or lang == country:
383
-                    self.lang = lang
384
-                    modified = True
385
-                    break
386
-
387
-        # check if category/engine prefix is set
388
-        elif query_parts[0].startswith('!'):
389
-            prefix = query_parts[0][1:].replace('_', ' ')
390
-
391
-            # check if prefix is equal with engine shortcut
392
-            if prefix in engine_shortcuts\
393
-               and not engine_shortcuts[prefix] in self.blocked_engines:
394
-                modified = True
395
-                self.engines.append({'category': 'none',
396
-                                     'name': engine_shortcuts[prefix]})
397
-
398
-            # check if prefix is equal with engine name
399
-            elif prefix in engines\
400
-                    and not prefix in self.blocked_engines:
401
-                modified = True
402
-                self.engines.append({'category': 'none',
403
-                                    'name': prefix})
404
-
405
-            # check if prefix is equal with categorie name
406
-            elif prefix in categories:
407
-                modified = True
408
-                # using all engines for that search, which are declared under that categorie name
409
-                self.engines.extend({'category': prefix,
410
-                                    'name': engine.name}
411
-                                    for engine in categories[prefix]
412
-                                    if not engine in self.blocked_engines)
413
-
414
-        # if language, category or engine were specificed in this query, search for more tags which does the same
415
-        if modified:
416
-            self.query = self.query.replace(query_parts[0], '', 1).strip()
417
-            self.parse_query()
418
-
419 374
     # do search-request
420 375
     def search(self, request):
421 376
         global number_of_searches

+ 2
- 2
searx/translations/fr/LC_MESSAGES/messages.po 查看文件

@@ -23,11 +23,11 @@ msgstr ""
23 23
 
24 24
 #: searx/webapp.py:167
25 25
 msgid "{minutes} minute(s) ago"
26
-msgstr ""
26
+msgstr "Il y a {minutes} minute(s)"
27 27
 
28 28
 #: searx/webapp.py:169
29 29
 msgid "{hours} hour(s), {minutes} minute(s) ago"
30
-msgstr ""
30
+msgstr "Il y a {hours} heure(s), {minutes} minute(s)"
31 31
 
32 32
 #: searx/engines/__init__.py:311
33 33
 msgid "Page loads (sec)"

+ 27
- 3
searx/webapp.py 查看文件

@@ -47,6 +47,7 @@ from searx.utils import (
47 47
 from searx.https_rewrite import https_rules
48 48
 from searx.languages import language_codes
49 49
 from searx.search import Search
50
+from searx.query import Query
50 51
 from searx.autocomplete import backends as autocomplete_backends
51 52
 
52 53
 
@@ -310,23 +311,46 @@ def autocompleter():
310 311
     """Return autocompleter results"""
311 312
     request_data = {}
312 313
 
314
+    # select request method
313 315
     if request.method == 'POST':
314 316
         request_data = request.form
315 317
     else:
316 318
         request_data = request.args
317 319
 
318
-    query = request_data.get('q', '').encode('utf-8')
320
+    # set blocked engines
321
+    if request.cookies.get('blocked_engines'):
322
+        blocked_engines = request.cookies['blocked_engines'].split(',')  # noqa
323
+    else:
324
+        blocked_engines = []
325
+
326
+    # parse query
327
+    query = Query(request_data.get('q', '').encode('utf-8'), blocked_engines)
328
+    query.parse_query()
319 329
 
320
-    if not query:
330
+    # check if search query is set
331
+    if not query.getSearchQuery():
321 332
         return
322 333
 
334
+    # run autocompleter
323 335
     completer = autocomplete_backends.get(request.cookies.get('autocomplete'))
324 336
 
337
+    # check if valid autocompleter is selected
325 338
     if not completer:
326 339
         return
327 340
 
328
-    results = completer(query)
341
+    # run autocompletion
342
+    raw_results = completer(query.getSearchQuery())
343
+
344
+    # parse results (write :language and !engine back to result string)
345
+    results = []
346
+    for result in raw_results:
347
+        result_query = query
348
+        result_query.changeSearchQuery(result)
349
+
350
+        # add parsed result
351
+        results.append(result_query.getFullQuery())
329 352
 
353
+    # return autocompleter results
330 354
     if request_data.get('format') == 'x-suggestions':
331 355
         return Response(json.dumps([query, results]),
332 356
                         mimetype='application/json')