on master help sign in
Merge remote-tracking branch 'upstream/master'
commit829c75897082b74b5301af6d6a27dc0cf9f5e7d6 authordalf <alex@al-f.net> dateWed 1 Oct 2014, 22:25 (12 years ago) parent0a71525fce6fb2
5 files changed+182−64
searx/engines/__init__.py+16−4 searx/query.py+127 searx/search.py+10−55 searx/translations/fr/LC_MESSAGES/messages.po+2−2 searx/webapp.py+27−3
searx/engines/__init__.py+16−4
@@ -142,16 +142,28 @@ def get_engines_stats():
142142 })
143143
144144 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
146149
147150 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
149155
150156 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
152161
153162 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
155167
156168 for engine in errors:
157169 if max_errors:
searx/query.pynew file+127
@@ -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+
searx/search.py+10−55
@@ -26,6 +26,7 @@ from searx.engines import (
2626)
2727from searx.languages import language_codes
2828from searx.utils import gen_useragent
29+from searx.query import Query
2930
3031
3132number_of_searches = 0
@@ -321,7 +322,15 @@ class Search(object):
321322 self.pageno = int(pageno_param)
322323
323324 # 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
325334
326335 self.categories = []
327336
@@ -362,60 +371,6 @@ class Search(object):
362371 for x in categories[categ]
363372 if not x.name in self.blocked_engines)
364373
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−
419374 # do search-request
420375 def search(self, request):
421376 global number_of_searches
searx/translations/fr/LC_MESSAGES/messages.po+2−2
@@ -23,11 +23,11 @@ msgstr ""
2323
2424#: searx/webapp.py:167
2525msgid "{minutes} minute(s) ago"
26−msgstr ""
26+msgstr "Il y a {minutes} minute(s)"
2727
2828#: searx/webapp.py:169
2929msgid "{hours} hour(s), {minutes} minute(s) ago"
30−msgstr ""
30+msgstr "Il y a {hours} heure(s), {minutes} minute(s)"
3131
3232#: searx/engines/__init__.py:311
3333msgid "Page loads (sec)"
searx/webapp.py+27−3
@@ -47,6 +47,7 @@ from searx.utils import (
4747from searx.https_rewrite import https_rules
4848from searx.languages import language_codes
4949from searx.search import Search
50+from searx.query import Query
5051from searx.autocomplete import backends as autocomplete_backends
5152
5253
@@ -310,23 +311,46 @@ def autocompleter():
310311 """Return autocompleter results"""
311312 request_data = {}
312313
314+ # select request method
313315 if request.method == 'POST':
314316 request_data = request.form
315317 else:
316318 request_data = request.args
317319
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()
319329
320− if not query:
330+ # check if search query is set
331+ if not query.getSearchQuery():
321332 return
322333
334+ # run autocompleter
323335 completer = autocomplete_backends.get(request.cookies.get('autocomplete'))
324336
337+ # check if valid autocompleter is selected
325338 if not completer:
326339 return
327340
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())
329352
353+ # return autocompleter results
330354 if request_data.get('format') == 'x-suggestions':
331355 return Response(json.dumps([query, results]),
332356 mimetype='application/json')