Browse Source

[enh] add ability to send engine data to subsequent requests

Adam Tauber 4 years ago
parent
commit
44f4a9d49a

+ 1 - 0
searx/engines/__init__.py

@@ -327,6 +327,7 @@ def _set_https_support_for_engine(engine):
             'is_test': True,
             'is_test': True,
             'category': 'files',
             'category': 'files',
             'raise_for_status': True,
             'raise_for_status': True,
+            'engine_data': {},
         })
         })
 
 
         if 'url' not in params:
         if 'url' not in params:

+ 5 - 1
searx/results.py

@@ -1,4 +1,5 @@
 import re
 import re
+from collections import defaultdict
 from operator import itemgetter
 from operator import itemgetter
 from threading import RLock
 from threading import RLock
 from urllib.parse import urlparse, unquote
 from urllib.parse import urlparse, unquote
@@ -144,7 +145,7 @@ class ResultContainer:
     """docstring for ResultContainer"""
     """docstring for ResultContainer"""
 
 
     __slots__ = '_merged_results', 'infoboxes', 'suggestions', 'answers', 'corrections', '_number_of_results',\
     __slots__ = '_merged_results', 'infoboxes', 'suggestions', 'answers', 'corrections', '_number_of_results',\
-                '_ordered', 'paging', 'unresponsive_engines', 'timings', 'redirect_url'
+                '_ordered', 'paging', 'unresponsive_engines', 'timings', 'redirect_url', 'engine_data'
 
 
     def __init__(self):
     def __init__(self):
         super().__init__()
         super().__init__()
@@ -154,6 +155,7 @@ class ResultContainer:
         self.answers = {}
         self.answers = {}
         self.corrections = set()
         self.corrections = set()
         self._number_of_results = []
         self._number_of_results = []
+        self.engine_data = defaultdict(dict)
         self._ordered = False
         self._ordered = False
         self.paging = False
         self.paging = False
         self.unresponsive_engines = set()
         self.unresponsive_engines = set()
@@ -175,6 +177,8 @@ class ResultContainer:
                 self._merge_infobox(result)
                 self._merge_infobox(result)
             elif 'number_of_results' in result:
             elif 'number_of_results' in result:
                 self._number_of_results.append(result['number_of_results'])
                 self._number_of_results.append(result['number_of_results'])
+            elif 'engine_data' in result:
+                self.engine_data[engine_name][result['key']] = result['engine_data']
             else:
             else:
                 # standard result (url, title, content)
                 # standard result (url, title, content)
                 if 'url' in result and not isinstance(result['url'], str):
                 if 'url' in result and not isinstance(result['url'], str):

+ 2 - 0
searx/search/__init__.py

@@ -111,6 +111,8 @@ class Search:
             if request_params is None:
             if request_params is None:
                 continue
                 continue
 
 
+            request_params['engine_data'] = self.search_query.engine_data.get(engineref.name, {})
+
             with threading.RLock():
             with threading.RLock():
                 processor.engine.stats['sent_search_count'] += 1
                 processor.engine.stats['sent_search_count'] += 1
 
 

+ 6 - 2
searx/search/models.py

@@ -25,7 +25,7 @@ class SearchQuery:
     """container for all the search parameters (query, language, etc...)"""
     """container for all the search parameters (query, language, etc...)"""
 
 
     __slots__ = 'query', 'engineref_list', 'lang', 'safesearch', 'pageno', 'time_range',\
     __slots__ = 'query', 'engineref_list', 'lang', 'safesearch', 'pageno', 'time_range',\
-                'timeout_limit', 'external_bang'
+                'timeout_limit', 'external_bang', 'engine_data'
 
 
     def __init__(self,
     def __init__(self,
                  query: str,
                  query: str,
@@ -35,7 +35,8 @@ class SearchQuery:
                  pageno: int=1,
                  pageno: int=1,
                  time_range: typing.Optional[str]=None,
                  time_range: typing.Optional[str]=None,
                  timeout_limit: typing.Optional[float]=None,
                  timeout_limit: typing.Optional[float]=None,
-                 external_bang: typing.Optional[str]=None):
+                 external_bang: typing.Optional[str]=None,
+                 engine_data: typing.Optional[dict]=None):
         self.query = query
         self.query = query
         self.engineref_list = engineref_list
         self.engineref_list = engineref_list
         self.lang = lang
         self.lang = lang
@@ -44,6 +45,9 @@ class SearchQuery:
         self.time_range = time_range
         self.time_range = time_range
         self.timeout_limit = timeout_limit
         self.timeout_limit = timeout_limit
         self.external_bang = external_bang
         self.external_bang = external_bang
+        self.engine_data = engine_data
+        if engine_data is None:
+            self.engine_data = {}
 
 
     @property
     @property
     def categories(self):
     def categories(self):

+ 11 - 0
searx/templates/oscar/results.html

@@ -7,6 +7,13 @@
     <input type="hidden" name="language" value="{{ current_language }}" />{{- "" -}}
     <input type="hidden" name="language" value="{{ current_language }}" />{{- "" -}}
     {% if timeout_limit %}<input type="hidden" name="timeout_limit" value="{{ timeout_limit|e }}" />{% endif -%}
     {% if timeout_limit %}<input type="hidden" name="timeout_limit" value="{{ timeout_limit|e }}" />{% endif -%}
 {%- endmacro %}
 {%- endmacro %}
+{% macro engine_data_form(engine_data) -%}
+    {% for engine_name, kv_data in engine_data.items() %}
+        {% for k, v in kv_data.items() %}
+            <input type="hidden" name="engine_data-{{ engine_name }}-{{ k|e }}" value="{{ v|e }}" />
+        {% endfor %}
+    {% endfor %}
+{%- endmacro %}
 {%- macro search_url() %}{{ url_for('search', _external=True) }}?q={{ q|urlencode }}{% if selected_categories %}&amp;categories={{ selected_categories|join(",") | replace(' ','+') }}{% endif %}{% if pageno > 1 %}&amp;pageno={{ pageno }}{% endif %}{% if time_range %}&amp;time_range={{ time_range }}{% endif %}{% if current_language != 'all' %}&amp;language={{ current_language }}{% endif %}{% endmacro -%}
 {%- macro search_url() %}{{ url_for('search', _external=True) }}?q={{ q|urlencode }}{% if selected_categories %}&amp;categories={{ selected_categories|join(",") | replace(' ','+') }}{% endif %}{% if pageno > 1 %}&amp;pageno={{ pageno }}{% endif %}{% if time_range %}&amp;time_range={{ time_range }}{% endif %}{% if current_language != 'all' %}&amp;language={{ current_language }}{% endif %}{% endmacro -%}
 
 
 {% block title %}{{ q|e }} - {% endblock %}
 {% block title %}{{ q|e }} - {% endblock %}
@@ -142,12 +149,14 @@
                 <div class="pull-left">{{- "" -}}
                 <div class="pull-left">{{- "" -}}
                   <form method="{{ method or 'POST' }}" action="{{ url_for('search') }}" class="pull-left">
                   <form method="{{ method or 'POST' }}" action="{{ url_for('search') }}" class="pull-left">
                         {{- search_form_attrs(pageno+1) -}}
                         {{- search_form_attrs(pageno+1) -}}
+                        {{- engine_data_form(engine_data) -}}
                         <button type="submit" class="btn btn-default"><span class="glyphicon glyphicon-backward"></span> {{ _('next page') }}</button>{{- "" -}}
                         <button type="submit" class="btn btn-default"><span class="glyphicon glyphicon-backward"></span> {{ _('next page') }}</button>{{- "" -}}
                     </form>{{- "" -}}
                     </form>{{- "" -}}
                 </div>
                 </div>
                 <div class="pull-right">{{- "" -}}
                 <div class="pull-right">{{- "" -}}
                     <form method="{{ method or 'POST' }}" action="{{ url_for('search') }}"  class="pull-left">
                     <form method="{{ method or 'POST' }}" action="{{ url_for('search') }}"  class="pull-left">
                         {{- search_form_attrs(pageno-1) -}}
                         {{- search_form_attrs(pageno-1) -}}
+                        {{- engine_data_form(engine_data) -}}
                         <button type="submit" class="btn btn-default" {% if pageno == 1 %}disabled{% endif %}><span class="glyphicon glyphicon-forward"></span> {{ _('previous page') }}</button>{{- "" -}}
                         <button type="submit" class="btn btn-default" {% if pageno == 1 %}disabled{% endif %}><span class="glyphicon glyphicon-forward"></span> {{ _('previous page') }}</button>{{- "" -}}
                     </form>{{- "" -}}
                     </form>{{- "" -}}
                 </div>
                 </div>
@@ -158,12 +167,14 @@
                 <div class="pull-left">{{- "" -}}
                 <div class="pull-left">{{- "" -}}
                     <form method="{{ method or 'POST' }}" action="{{ url_for('search') }}" class="pull-left">
                     <form method="{{ method or 'POST' }}" action="{{ url_for('search') }}" class="pull-left">
                         {{- search_form_attrs(pageno-1) -}}
                         {{- search_form_attrs(pageno-1) -}}
+                        {{- engine_data_form(engine_data) -}}
                         <button type="submit" class="btn btn-default" {% if pageno == 1 %}disabled{% endif %}><span class="glyphicon glyphicon-backward"></span> {{ _('previous page') }}</button>{{- "" -}}
                         <button type="submit" class="btn btn-default" {% if pageno == 1 %}disabled{% endif %}><span class="glyphicon glyphicon-backward"></span> {{ _('previous page') }}</button>{{- "" -}}
                     </form>{{- "" -}}
                     </form>{{- "" -}}
                 </div>
                 </div>
                 <div class="pull-right">{{- "" -}}
                 <div class="pull-right">{{- "" -}}
                     <form method="{{ method or 'POST' }}" action="{{ url_for('search') }}"  class="pull-left">
                     <form method="{{ method or 'POST' }}" action="{{ url_for('search') }}"  class="pull-left">
                         {{- search_form_attrs(pageno+1) -}}
                         {{- search_form_attrs(pageno+1) -}}
+                        {{- engine_data_form(engine_data) -}}
                         <button type="submit" class="btn btn-default"><span class="glyphicon glyphicon-forward"></span> {{ _('next page') }}</button>{{- "" -}}
                         <button type="submit" class="btn btn-default"><span class="glyphicon glyphicon-forward"></span> {{ _('next page') }}</button>{{- "" -}}
                     </form>{{- "" -}}
                     </form>{{- "" -}}
                 </div>
                 </div>

+ 9 - 0
searx/templates/simple/results.html

@@ -1,5 +1,12 @@
 {% extends "simple/base.html" %}
 {% extends "simple/base.html" %}
 {% from 'simple/macros.html' import icon, icon_small %}
 {% from 'simple/macros.html' import icon, icon_small %}
+{% macro engine_data_form(engine_data) -%}
+    {% for engine_name, kv_data in engine_data.items() %}
+        {% for k, v in kv_data.items() %}
+            <input type="hidden" name="engine_data-{{ engine_name }}-{{ k|e }}" value="{{ v|e }}" />
+        {% endfor %}
+    {% endfor %}
+{%- endmacro %}
 {% block title %}{% if method == 'GET' %}{{- q|e -}} -{% endif %}{% endblock %}
 {% block title %}{% if method == 'GET' %}{{- q|e -}} -{% endif %}{% endblock %}
 {% block meta %}<link rel="alternate" type="application/rss+xml" title="Searx search: {{ q|e }}" href="{{ url_for('search', _external=True) }}?q={{ q|urlencode }}&amp;categories={{ selected_categories|join(",") | replace(' ','+') }}&amp;pageno={{ pageno }}&amp;time_range={{ time_range }}&amp;language={{ current_language }}&amp;safesearch={{ safesearch }}&amp;format=rss">{% endblock %}
 {% block meta %}<link rel="alternate" type="application/rss+xml" title="Searx search: {{ q|e }}" href="{{ url_for('search', _external=True) }}?q={{ q|urlencode }}&amp;categories={{ selected_categories|join(",") | replace(' ','+') }}&amp;pageno={{ pageno }}&amp;time_range={{ time_range }}&amp;language={{ current_language }}&amp;safesearch={{ safesearch }}&amp;format=rss">{% endblock %}
 {% block content %}
 {% block content %}
@@ -136,6 +143,7 @@
             <form method="{{ method or 'POST' }}" action="{{ url_for('search') }}">
             <form method="{{ method or 'POST' }}" action="{{ url_for('search') }}">
                 <div class="{% if rtl %}right{% else %}left{% endif %}">
                 <div class="{% if rtl %}right{% else %}left{% endif %}">
                   <input type="hidden" name="q" value="{{ q|e }}" >
                   <input type="hidden" name="q" value="{{ q|e }}" >
+                  {{- engine_data_form(engine_data) -}}
                   {% for category in selected_categories %}
                   {% for category in selected_categories %}
                   <input type="hidden" name="category_{{ category }}" value="1" >
                   <input type="hidden" name="category_{{ category }}" value="1" >
                   {% endfor %}
                   {% endfor %}
@@ -152,6 +160,7 @@
         <form method="{{ method or 'POST' }}" action="{{ url_for('search') }}">
         <form method="{{ method or 'POST' }}" action="{{ url_for('search') }}">
             <div class="{% if rtl %}left{% else %}right{% endif %}">
             <div class="{% if rtl %}left{% else %}right{% endif %}">
               <input type="hidden" name="q" value="{{ q|e }}" >
               <input type="hidden" name="q" value="{{ q|e }}" >
+              {{- engine_data_form(engine_data) -}}
               {% for category in selected_categories %}
               {% for category in selected_categories %}
               <input type="hidden" name="category_{{ category }}" value="1" >
               <input type="hidden" name="category_{{ category }}" value="1" >
               {% endfor %}
               {% endfor %}

+ 13 - 1
searx/webadapter.py

@@ -1,3 +1,4 @@
+from collections import defaultdict
 from typing import Dict, List, Optional, Tuple
 from typing import Dict, List, Optional, Tuple
 from searx.exceptions import SearxParameterException
 from searx.exceptions import SearxParameterException
 from searx.webutils import VALID_LANGUAGE_CODE
 from searx.webutils import VALID_LANGUAGE_CODE
@@ -196,6 +197,15 @@ def parse_generic(preferences: Preferences, form: Dict[str, str], disabled_engin
     return query_engineref_list
     return query_engineref_list
 
 
 
 
+def parse_engine_data(form):
+    engine_data = defaultdict(dict)
+    for k, v in form.items():
+        if k.startswith("engine_data"):
+            _, engine, key = k.split('-')
+            engine_data[engine][key] = v
+    return engine_data
+
+
 def get_search_query_from_webapp(preferences: Preferences, form: Dict[str, str])\
 def get_search_query_from_webapp(preferences: Preferences, form: Dict[str, str])\
         -> Tuple[SearchQuery, RawTextQuery, List[EngineRef], List[EngineRef]]:
         -> Tuple[SearchQuery, RawTextQuery, List[EngineRef], List[EngineRef]]:
     # no text for the query ?
     # no text for the query ?
@@ -217,6 +227,7 @@ def get_search_query_from_webapp(preferences: Preferences, form: Dict[str, str])
     query_time_range = parse_time_range(form)
     query_time_range = parse_time_range(form)
     query_timeout = parse_timeout(form, raw_text_query)
     query_timeout = parse_timeout(form, raw_text_query)
     external_bang = raw_text_query.external_bang
     external_bang = raw_text_query.external_bang
+    engine_data = parse_engine_data(form)
 
 
     if not is_locked('categories') and raw_text_query.enginerefs and raw_text_query.specific:
     if not is_locked('categories') and raw_text_query.enginerefs and raw_text_query.specific:
         # if engines are calculated from query,
         # if engines are calculated from query,
@@ -232,7 +243,8 @@ def get_search_query_from_webapp(preferences: Preferences, form: Dict[str, str])
         validate_engineref_list(query_engineref_list, preferences)
         validate_engineref_list(query_engineref_list, preferences)
 
 
     return (SearchQuery(query, query_engineref_list, query_lang, query_safesearch, query_pageno,
     return (SearchQuery(query, query_engineref_list, query_lang, query_safesearch, query_pageno,
-                        query_time_range, query_timeout, external_bang=external_bang),
+                        query_time_range, query_timeout, external_bang=external_bang,
+                        engine_data=engine_data),
             raw_text_query,
             raw_text_query,
             query_engineref_list_unknown,
             query_engineref_list_unknown,
             query_engineref_list_notoken)
             query_engineref_list_notoken)

+ 1 - 0
searx/webapp.py

@@ -730,6 +730,7 @@ def search():
         answers=result_container.answers,
         answers=result_container.answers,
         corrections=correction_urls,
         corrections=correction_urls,
         infoboxes=result_container.infoboxes,
         infoboxes=result_container.infoboxes,
+        engine_data=result_container.engine_data,
         paging=result_container.paging,
         paging=result_container.paging,
         unresponsive_engines=__get_translated_errors(result_container.unresponsive_engines),
         unresponsive_engines=__get_translated_errors(result_container.unresponsive_engines),
         current_language=match_language(search_query.lang,
         current_language=match_language(search_query.lang,

+ 2 - 1
tests/unit/test_webapp.py

@@ -57,7 +57,8 @@ class ViewsTestCase(SearxTestCase):
                                                 results_number=lambda: 3,
                                                 results_number=lambda: 3,
                                                 results_length=lambda: len(test_results),
                                                 results_length=lambda: len(test_results),
                                                 get_timings=lambda: timings,
                                                 get_timings=lambda: timings,
-                                                redirect_url=None)
+                                                redirect_url=None,
+                                                engine_data={})
 
 
         self.setattr4test(Search, 'search', search_mock)
         self.setattr4test(Search, 'search', search_mock)