| 
				
			 | 
			
			
				@@ -41,6 +41,7 @@ from searx.engines import ( 
			 | 
		
	
		
			
			| 
				41
			 | 
			
				41
			 | 
			
			
				 from searx.utils import UnicodeWriter, highlight_content, html_to_text 
			 | 
		
	
		
			
			| 
				42
			 | 
			
				42
			 | 
			
			
				 from searx.languages import language_codes 
			 | 
		
	
		
			
			| 
				43
			 | 
			
				43
			 | 
			
			
				 from searx.search import Search 
			 | 
		
	
		
			
			| 
				
			 | 
			
				44
			 | 
			
			
				+from searx.autocomplete import backends as autocomplete_backends 
			 | 
		
	
		
			
			| 
				44
			 | 
			
				45
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				45
			 | 
			
				46
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				46
			 | 
			
				47
			 | 
			
			
				 app = Flask( 
			 | 
		
	
	
		
			
			| 
				
			 | 
			
			
				@@ -91,16 +92,25 @@ def get_base_url(): 
			 | 
		
	
		
			
			| 
				91
			 | 
			
				92
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				92
			 | 
			
				93
			 | 
			
			
				 def render(template_name, **kwargs): 
			 | 
		
	
		
			
			| 
				93
			 | 
			
				94
			 | 
			
			
				     blocked_engines = request.cookies.get('blocked_engines', '').split(',') 
			 | 
		
	
		
			
			| 
				
			 | 
			
				95
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				96
			 | 
			
			
				+    autocomplete = request.cookies.get('autocomplete') 
			 | 
		
	
		
			
			| 
				
			 | 
			
				97
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				98
			 | 
			
			
				+    if autocomplete not in autocomplete_backends: 
			 | 
		
	
		
			
			| 
				
			 | 
			
				99
			 | 
			
			
				+        autocomplete = None 
			 | 
		
	
		
			
			| 
				
			 | 
			
				100
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				94
			 | 
			
				101
			 | 
			
			
				     nonblocked_categories = (engines[e].categories 
			 | 
		
	
		
			
			| 
				95
			 | 
			
				102
			 | 
			
			
				                              for e in engines 
			 | 
		
	
		
			
			| 
				96
			 | 
			
				103
			 | 
			
			
				                              if e not in blocked_engines) 
			 | 
		
	
		
			
			| 
				
			 | 
			
				104
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				97
			 | 
			
				105
			 | 
			
			
				     nonblocked_categories = set(chain.from_iterable(nonblocked_categories)) 
			 | 
		
	
		
			
			| 
				
			 | 
			
				106
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				98
			 | 
			
				107
			 | 
			
			
				     if not 'categories' in kwargs: 
			 | 
		
	
		
			
			| 
				99
			 | 
			
				108
			 | 
			
			
				         kwargs['categories'] = ['general'] 
			 | 
		
	
		
			
			| 
				100
			 | 
			
				109
			 | 
			
			
				         kwargs['categories'].extend(x for x in 
			 | 
		
	
		
			
			| 
				101
			 | 
			
				110
			 | 
			
			
				                                     sorted(categories.keys()) 
			 | 
		
	
		
			
			| 
				102
			 | 
			
				111
			 | 
			
			
				                                     if x != 'general' 
			 | 
		
	
		
			
			| 
				103
			 | 
			
				112
			 | 
			
			
				                                     and x in nonblocked_categories) 
			 | 
		
	
		
			
			| 
				
			 | 
			
				113
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				104
			 | 
			
				114
			 | 
			
			
				     if not 'selected_categories' in kwargs: 
			 | 
		
	
		
			
			| 
				105
			 | 
			
				115
			 | 
			
			
				         kwargs['selected_categories'] = [] 
			 | 
		
	
		
			
			| 
				106
			 | 
			
				116
			 | 
			
			
				         cookie_categories = request.cookies.get('categories', '').split(',') 
			 | 
		
	
	
		
			
			| 
				
			 | 
			
			
				@@ -109,6 +119,10 @@ def render(template_name, **kwargs): 
			 | 
		
	
		
			
			| 
				109
			 | 
			
				119
			 | 
			
			
				                 kwargs['selected_categories'].append(ccateg) 
			 | 
		
	
		
			
			| 
				110
			 | 
			
				120
			 | 
			
			
				         if not kwargs['selected_categories']: 
			 | 
		
	
		
			
			| 
				111
			 | 
			
				121
			 | 
			
			
				             kwargs['selected_categories'] = ['general'] 
			 | 
		
	
		
			
			| 
				
			 | 
			
				122
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				123
			 | 
			
			
				+    if not 'autocomplete' in kwargs: 
			 | 
		
	
		
			
			| 
				
			 | 
			
				124
			 | 
			
			
				+        kwargs['autocomplete'] = autocomplete 
			 | 
		
	
		
			
			| 
				
			 | 
			
				125
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				112
			 | 
			
				126
			 | 
			
			
				     return render_template(template_name, **kwargs) 
			 | 
		
	
		
			
			| 
				113
			 | 
			
				127
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				114
			 | 
			
				128
			 | 
			
			
				  
			 | 
		
	
	
		
			
			| 
				
			 | 
			
			
				@@ -122,7 +136,6 @@ def index(): 
			 | 
		
	
		
			
			| 
				122
			 | 
			
				136
			 | 
			
			
				     if not request.args and not request.form: 
			 | 
		
	
		
			
			| 
				123
			 | 
			
				137
			 | 
			
			
				         return render( 
			 | 
		
	
		
			
			| 
				124
			 | 
			
				138
			 | 
			
			
				             'index.html', 
			 | 
		
	
		
			
			| 
				125
			 | 
			
				
			 | 
			
			
				-            client=settings.get('client', None) 
			 | 
		
	
		
			
			| 
				126
			 | 
			
				139
			 | 
			
			
				         ) 
			 | 
		
	
		
			
			| 
				127
			 | 
			
				140
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				128
			 | 
			
				141
			 | 
			
			
				     try: 
			 | 
		
	
	
		
			
			| 
				
			 | 
			
			
				@@ -130,7 +143,6 @@ def index(): 
			 | 
		
	
		
			
			| 
				130
			 | 
			
				143
			 | 
			
			
				     except: 
			 | 
		
	
		
			
			| 
				131
			 | 
			
				144
			 | 
			
			
				         return render( 
			 | 
		
	
		
			
			| 
				132
			 | 
			
				145
			 | 
			
			
				             'index.html', 
			 | 
		
	
		
			
			| 
				133
			 | 
			
				
			 | 
			
			
				-            client=settings.get('client', None) 
			 | 
		
	
		
			
			| 
				134
			 | 
			
				146
			 | 
			
			
				         ) 
			 | 
		
	
		
			
			| 
				135
			 | 
			
				147
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				136
			 | 
			
				148
			 | 
			
			
				     # TODO moar refactor - do_search integration into Search class 
			 | 
		
	
	
		
			
			| 
				
			 | 
			
			
				@@ -212,7 +224,6 @@ def index(): 
			 | 
		
	
		
			
			| 
				212
			 | 
			
				224
			 | 
			
			
				     return render( 
			 | 
		
	
		
			
			| 
				213
			 | 
			
				225
			 | 
			
			
				         'results.html', 
			 | 
		
	
		
			
			| 
				214
			 | 
			
				226
			 | 
			
			
				         results=search.results, 
			 | 
		
	
		
			
			| 
				215
			 | 
			
				
			 | 
			
			
				-        client=settings.get('client', None), 
			 | 
		
	
		
			
			| 
				216
			 | 
			
				227
			 | 
			
			
				         q=search.request_data['q'], 
			 | 
		
	
		
			
			| 
				217
			 | 
			
				228
			 | 
			
			
				         selected_categories=search.categories, 
			 | 
		
	
		
			
			| 
				218
			 | 
			
				229
			 | 
			
			
				         paging=search.paging, 
			 | 
		
	
	
		
			
			| 
				
			 | 
			
			
				@@ -227,7 +238,6 @@ def about(): 
			 | 
		
	
		
			
			| 
				227
			 | 
			
				238
			 | 
			
			
				     """Render about page""" 
			 | 
		
	
		
			
			| 
				228
			 | 
			
				239
			 | 
			
			
				     return render( 
			 | 
		
	
		
			
			| 
				229
			 | 
			
				240
			 | 
			
			
				         'about.html', 
			 | 
		
	
		
			
			| 
				230
			 | 
			
				
			 | 
			
			
				-        client=settings.get('client', None) 
			 | 
		
	
		
			
			| 
				231
			 | 
			
				241
			 | 
			
			
				     ) 
			 | 
		
	
		
			
			| 
				232
			 | 
			
				242
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				233
			 | 
			
				243
			 | 
			
			
				  
			 | 
		
	
	
		
			
			| 
				
			 | 
			
			
				@@ -235,27 +245,35 @@ def about(): 
			 | 
		
	
		
			
			| 
				235
			 | 
			
				245
			 | 
			
			
				 def autocompleter(): 
			 | 
		
	
		
			
			| 
				236
			 | 
			
				246
			 | 
			
			
				     """Return autocompleter results""" 
			 | 
		
	
		
			
			| 
				237
			 | 
			
				247
			 | 
			
			
				     request_data = {} 
			 | 
		
	
		
			
			| 
				238
			 | 
			
				
			 | 
			
			
				-     
			 | 
		
	
		
			
			| 
				
			 | 
			
				248
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				239
			 | 
			
				249
			 | 
			
			
				     if request.method == 'POST': 
			 | 
		
	
		
			
			| 
				240
			 | 
			
				250
			 | 
			
			
				         request_data = request.form 
			 | 
		
	
		
			
			| 
				241
			 | 
			
				251
			 | 
			
			
				     else: 
			 | 
		
	
		
			
			| 
				242
			 | 
			
				252
			 | 
			
			
				         request_data = request.args 
			 | 
		
	
		
			
			| 
				243
			 | 
			
				
			 | 
			
			
				-     
			 | 
		
	
		
			
			| 
				
			 | 
			
				253
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				244
			 | 
			
				254
			 | 
			
			
				     # TODO fix XSS-vulnerability 
			 | 
		
	
		
			
			| 
				245
			 | 
			
				
			 | 
			
			
				-    autocompleter.querry = request_data.get('q') 
			 | 
		
	
		
			
			| 
				246
			 | 
			
				
			 | 
			
			
				-    autocompleter.results = [] 
			 | 
		
	
		
			
			| 
				247
			 | 
			
				
			 | 
			
			
				-     
			 | 
		
	
		
			
			| 
				248
			 | 
			
				
			 | 
			
			
				-    if settings['client']['autocompleter']: 
			 | 
		
	
		
			
			| 
				249
			 | 
			
				
			 | 
			
			
				-        #TODO remove test code and add real autocompletion 
			 | 
		
	
		
			
			| 
				250
			 | 
			
				
			 | 
			
			
				-        if autocompleter.querry: 
			 | 
		
	
		
			
			| 
				251
			 | 
			
				
			 | 
			
			
				-            autocompleter.results = [autocompleter.querry + " result-1",autocompleter.querry + " result-2",autocompleter.querry + " result-3",autocompleter.querry + " result-4"] 
			 | 
		
	
		
			
			| 
				252
			 | 
			
				
			 | 
			
			
				-     
			 | 
		
	
		
			
			| 
				
			 | 
			
				255
			 | 
			
			
				+    query = request_data.get('q') 
			 | 
		
	
		
			
			| 
				
			 | 
			
				256
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				257
			 | 
			
			
				+    if not query: 
			 | 
		
	
		
			
			| 
				
			 | 
			
				258
			 | 
			
			
				+        return 
			 | 
		
	
		
			
			| 
				
			 | 
			
				259
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				260
			 | 
			
			
				+    completer = autocomplete_backends.get(request.cookies.get('autocomplete')) 
			 | 
		
	
		
			
			| 
				
			 | 
			
				261
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				262
			 | 
			
			
				+    if not completer: 
			 | 
		
	
		
			
			| 
				
			 | 
			
				263
			 | 
			
			
				+        return 
			 | 
		
	
		
			
			| 
				
			 | 
			
				264
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				265
			 | 
			
			
				+    try: 
			 | 
		
	
		
			
			| 
				
			 | 
			
				266
			 | 
			
			
				+        results = completer(query) 
			 | 
		
	
		
			
			| 
				
			 | 
			
				267
			 | 
			
			
				+    except Exception, e: 
			 | 
		
	
		
			
			| 
				
			 | 
			
				268
			 | 
			
			
				+        print e 
			 | 
		
	
		
			
			| 
				
			 | 
			
				269
			 | 
			
			
				+        results = [] 
			 | 
		
	
		
			
			| 
				
			 | 
			
				270
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				253
			 | 
			
				271
			 | 
			
			
				     if request_data.get('format') == 'x-suggestions': 
			 | 
		
	
		
			
			| 
				254
			 | 
			
				
			 | 
			
			
				-        return Response(json.dumps([autocompleter.querry,autocompleter.results]), 
			 | 
		
	
		
			
			| 
				255
			 | 
			
				
			 | 
			
			
				-                                   mimetype='application/json') 
			 | 
		
	
		
			
			| 
				
			 | 
			
				272
			 | 
			
			
				+        return Response(json.dumps([query, results]), 
			 | 
		
	
		
			
			| 
				
			 | 
			
				273
			 | 
			
			
				+                        mimetype='application/json') 
			 | 
		
	
		
			
			| 
				256
			 | 
			
				274
			 | 
			
			
				     else: 
			 | 
		
	
		
			
			| 
				257
			 | 
			
				
			 | 
			
			
				-        return Response(json.dumps(autocompleter.results), 
			 | 
		
	
		
			
			| 
				258
			 | 
			
				
			 | 
			
			
				-                                   mimetype='application/json') 
			 | 
		
	
		
			
			| 
				
			 | 
			
				275
			 | 
			
			
				+        return Response(json.dumps(results), 
			 | 
		
	
		
			
			| 
				
			 | 
			
				276
			 | 
			
			
				+                        mimetype='application/json') 
			 | 
		
	
		
			
			| 
				259
			 | 
			
				277
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				260
			 | 
			
				278
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				261
			 | 
			
				279
			 | 
			
			
				 @app.route('/preferences', methods=['GET', 'POST']) 
			 | 
		
	
	
		
			
			| 
				
			 | 
			
			
				@@ -276,6 +294,7 @@ def preferences(): 
			 | 
		
	
		
			
			| 
				276
			 | 
			
				294
			 | 
			
			
				     else: 
			 | 
		
	
		
			
			| 
				277
			 | 
			
				295
			 | 
			
			
				         selected_categories = [] 
			 | 
		
	
		
			
			| 
				278
			 | 
			
				296
			 | 
			
			
				         locale = None 
			 | 
		
	
		
			
			| 
				
			 | 
			
				297
			 | 
			
			
				+        autocomplete = '' 
			 | 
		
	
		
			
			| 
				279
			 | 
			
				298
			 | 
			
			
				         for pd_name, pd in request.form.items(): 
			 | 
		
	
		
			
			| 
				280
			 | 
			
				299
			 | 
			
			
				             if pd_name.startswith('category_'): 
			 | 
		
	
		
			
			| 
				281
			 | 
			
				300
			 | 
			
			
				                 category = pd_name[9:] 
			 | 
		
	
	
		
			
			| 
				
			 | 
			
			
				@@ -284,6 +303,8 @@ def preferences(): 
			 | 
		
	
		
			
			| 
				284
			 | 
			
				303
			 | 
			
			
				                 selected_categories.append(category) 
			 | 
		
	
		
			
			| 
				285
			 | 
			
				304
			 | 
			
			
				             elif pd_name == 'locale' and pd in settings['locales']: 
			 | 
		
	
		
			
			| 
				286
			 | 
			
				305
			 | 
			
			
				                 locale = pd 
			 | 
		
	
		
			
			| 
				
			 | 
			
				306
			 | 
			
			
				+            elif pd_name == 'autocomplete': 
			 | 
		
	
		
			
			| 
				
			 | 
			
				307
			 | 
			
			
				+                autocomplete = pd 
			 | 
		
	
		
			
			| 
				287
			 | 
			
				308
			 | 
			
			
				             elif pd_name == 'language' and (pd == 'all' or 
			 | 
		
	
		
			
			| 
				288
			 | 
			
				309
			 | 
			
			
				                                             pd in (x[0] for 
			 | 
		
	
		
			
			| 
				289
			 | 
			
				310
			 | 
			
			
				                                                    x in language_codes)): 
			 | 
		
	
	
		
			
			| 
				
			 | 
			
			
				@@ -319,8 +340,14 @@ def preferences(): 
			 | 
		
	
		
			
			| 
				319
			 | 
			
				340
			 | 
			
			
				             # cookie max age: 4 weeks 
			 | 
		
	
		
			
			| 
				320
			 | 
			
				341
			 | 
			
			
				             resp.set_cookie( 
			 | 
		
	
		
			
			| 
				321
			 | 
			
				342
			 | 
			
			
				                 'categories', ','.join(selected_categories), 
			 | 
		
	
		
			
			| 
				322
			 | 
			
				
			 | 
			
			
				-                max_age=60 * 60 * 24 * 7 * 4 
			 | 
		
	
		
			
			| 
				
			 | 
			
				343
			 | 
			
			
				+                max_age=cookie_max_age 
			 | 
		
	
		
			
			| 
				323
			 | 
			
				344
			 | 
			
			
				             ) 
			 | 
		
	
		
			
			| 
				
			 | 
			
				345
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				346
			 | 
			
			
				+            resp.set_cookie( 
			 | 
		
	
		
			
			| 
				
			 | 
			
				347
			 | 
			
			
				+                'autocomplete', autocomplete, 
			 | 
		
	
		
			
			| 
				
			 | 
			
				348
			 | 
			
			
				+                max_age=cookie_max_age 
			 | 
		
	
		
			
			| 
				
			 | 
			
				349
			 | 
			
			
				+            ) 
			 | 
		
	
		
			
			| 
				
			 | 
			
				350
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				324
			 | 
			
				351
			 | 
			
			
				         return resp 
			 | 
		
	
		
			
			| 
				325
			 | 
			
				352
			 | 
			
			
				     return render('preferences.html', 
			 | 
		
	
		
			
			| 
				326
			 | 
			
				353
			 | 
			
			
				                   client=settings.get('client', None), 
			 | 
		
	
	
		
			
			| 
				
			 | 
			
			
				@@ -330,6 +357,7 @@ def preferences(): 
			 | 
		
	
		
			
			| 
				330
			 | 
			
				357
			 | 
			
			
				                   language_codes=language_codes, 
			 | 
		
	
		
			
			| 
				331
			 | 
			
				358
			 | 
			
			
				                   categs=categories.items(), 
			 | 
		
	
		
			
			| 
				332
			 | 
			
				359
			 | 
			
			
				                   blocked_engines=blocked_engines, 
			 | 
		
	
		
			
			| 
				
			 | 
			
				360
			 | 
			
			
				+                  autocomplete_backends=autocomplete_backends, 
			 | 
		
	
		
			
			| 
				333
			 | 
			
				361
			 | 
			
			
				                   shortcuts={y: x for x, y in engine_shortcuts.items()}) 
			 | 
		
	
		
			
			| 
				334
			 | 
			
				362
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				335
			 | 
			
				363
			 | 
			
			
				  
			 | 
		
	
	
		
			
			| 
				
			 | 
			
			
				@@ -361,7 +389,12 @@ def opensearch(): 
			 | 
		
	
		
			
			| 
				361
			 | 
			
				389
			 | 
			
			
				     # chrome/chromium only supports HTTP GET.... 
			 | 
		
	
		
			
			| 
				362
			 | 
			
				390
			 | 
			
			
				     if request.headers.get('User-Agent', '').lower().find('webkit') >= 0: 
			 | 
		
	
		
			
			| 
				363
			 | 
			
				391
			 | 
			
			
				         method = 'get' 
			 | 
		
	
		
			
			| 
				364
			 | 
			
				
			 | 
			
			
				-    ret = render('opensearch.xml', method=method, host=get_base_url(),client=settings['client']) 
			 | 
		
	
		
			
			| 
				
			 | 
			
				392
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				393
			 | 
			
			
				+    ret = render('opensearch.xml', 
			 | 
		
	
		
			
			| 
				
			 | 
			
				394
			 | 
			
			
				+                 method=method, 
			 | 
		
	
		
			
			| 
				
			 | 
			
				395
			 | 
			
			
				+                 host=get_base_url(), 
			 | 
		
	
		
			
			| 
				
			 | 
			
				396
			 | 
			
			
				+                 client=settings['client']) 
			 | 
		
	
		
			
			| 
				
			 | 
			
				397
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				365
			 | 
			
				398
			 | 
			
			
				     resp = Response(response=ret, 
			 | 
		
	
		
			
			| 
				366
			 | 
			
				399
			 | 
			
			
				                     status=200, 
			 | 
		
	
		
			
			| 
				367
			 | 
			
				400
			 | 
			
			
				                     mimetype="application/xml") 
			 |