[feat] implement feeling lucky feature
This commit is contained in:
		
							parent
							
								
									71508abcbf
								
							
						
					
					
						commit
						dcee823345
					
				| @ -150,7 +150,7 @@ class LanguageParser(QueryPartParser): | |||||||
| class ExternalBangParser(QueryPartParser): | class ExternalBangParser(QueryPartParser): | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def check(raw_value): |     def check(raw_value): | ||||||
|         return raw_value.startswith('!!') |         return raw_value.startswith('!!') and len(raw_value) > 2 | ||||||
| 
 | 
 | ||||||
|     def __call__(self, raw_value): |     def __call__(self, raw_value): | ||||||
|         value = raw_value[2:] |         value = raw_value[2:] | ||||||
| @ -177,7 +177,8 @@ class ExternalBangParser(QueryPartParser): | |||||||
| class BangParser(QueryPartParser): | class BangParser(QueryPartParser): | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def check(raw_value): |     def check(raw_value): | ||||||
|         return raw_value[0] == '!' |         # make sure it's not any bang with double '!!' | ||||||
|  |         return raw_value[0] == '!' and (len(raw_value) < 2 or raw_value[1] != '!') | ||||||
| 
 | 
 | ||||||
|     def __call__(self, raw_value): |     def __call__(self, raw_value): | ||||||
|         value = raw_value[1:].replace('-', ' ').replace('_', ' ') |         value = raw_value[1:].replace('-', ' ').replace('_', ' ') | ||||||
| @ -235,14 +236,25 @@ class BangParser(QueryPartParser): | |||||||
|                 self._add_autocomplete(first_char + engine_shortcut) |                 self._add_autocomplete(first_char + engine_shortcut) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | class FeelingLuckyParser(QueryPartParser): | ||||||
|  |     @staticmethod | ||||||
|  |     def check(raw_value): | ||||||
|  |         return raw_value == '!!' | ||||||
|  | 
 | ||||||
|  |     def __call__(self, raw_value): | ||||||
|  |         self.raw_text_query.redirect_to_first_result = True | ||||||
|  |         return True | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| class RawTextQuery: | class RawTextQuery: | ||||||
|     """parse raw text query (the value from the html input)""" |     """parse raw text query (the value from the html input)""" | ||||||
| 
 | 
 | ||||||
|     PARSER_CLASSES = [ |     PARSER_CLASSES = [ | ||||||
|         TimeoutParser,  # this force the timeout |         TimeoutParser,  # force the timeout | ||||||
|         LanguageParser,  # this force a language |         LanguageParser,  # force a language | ||||||
|         ExternalBangParser,  # external bang (must be before BangParser) |         ExternalBangParser,  # external bang (must be before BangParser) | ||||||
|         BangParser,  # this force a engine or category |         BangParser,  # force an engine or category | ||||||
|  |         FeelingLuckyParser,  # redirect to the first link in the results list | ||||||
|     ] |     ] | ||||||
| 
 | 
 | ||||||
|     def __init__(self, query, disabled_engines): |     def __init__(self, query, disabled_engines): | ||||||
| @ -261,6 +273,7 @@ class RawTextQuery: | |||||||
|         self.query_parts = []  # use self.getFullQuery() |         self.query_parts = []  # use self.getFullQuery() | ||||||
|         self.user_query_parts = []  # use self.getQuery() |         self.user_query_parts = []  # use self.getQuery() | ||||||
|         self.autocomplete_location = None |         self.autocomplete_location = None | ||||||
|  |         self.redirect_to_first_result = False | ||||||
|         self._parse_query() |         self._parse_query() | ||||||
| 
 | 
 | ||||||
|     def _parse_query(self): |     def _parse_query(self): | ||||||
| @ -330,5 +343,6 @@ class RawTextQuery: | |||||||
|             + f"enginerefs={self.enginerefs!r}\n  " |             + f"enginerefs={self.enginerefs!r}\n  " | ||||||
|             + f"autocomplete_list={self.autocomplete_list!r}\n  " |             + f"autocomplete_list={self.autocomplete_list!r}\n  " | ||||||
|             + f"query_parts={self.query_parts!r}\n  " |             + f"query_parts={self.query_parts!r}\n  " | ||||||
|             + f"user_query_parts={self.user_query_parts!r} >" |             + f"user_query_parts={self.user_query_parts!r} >\n" | ||||||
|  |             + f"redirect_to_first_result={self.redirect_to_first_result!r}" | ||||||
|         ) |         ) | ||||||
|  | |||||||
| @ -37,6 +37,7 @@ class SearchQuery: | |||||||
|         'timeout_limit', |         'timeout_limit', | ||||||
|         'external_bang', |         'external_bang', | ||||||
|         'engine_data', |         'engine_data', | ||||||
|  |         'redirect_to_first_result', | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
|     def __init__( |     def __init__( | ||||||
| @ -50,6 +51,7 @@ class SearchQuery: | |||||||
|         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[typing.Dict[str, str]] = None, |         engine_data: typing.Optional[typing.Dict[str, str]] = None, | ||||||
|  |         redirect_to_first_result: typing.Optional[bool] = None, | ||||||
|     ): |     ): | ||||||
|         self.query = query |         self.query = query | ||||||
|         self.engineref_list = engineref_list |         self.engineref_list = engineref_list | ||||||
| @ -60,6 +62,7 @@ class SearchQuery: | |||||||
|         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 or {} |         self.engine_data = engine_data or {} | ||||||
|  |         self.redirect_to_first_result = redirect_to_first_result | ||||||
| 
 | 
 | ||||||
|         self.locale = None |         self.locale = None | ||||||
|         if self.lang: |         if self.lang: | ||||||
| @ -73,7 +76,7 @@ class SearchQuery: | |||||||
|         return list(set(map(lambda engineref: engineref.category, self.engineref_list))) |         return list(set(map(lambda engineref: engineref.category, self.engineref_list))) | ||||||
| 
 | 
 | ||||||
|     def __repr__(self): |     def __repr__(self): | ||||||
|         return "SearchQuery({!r}, {!r}, {!r}, {!r}, {!r}, {!r}, {!r}, {!r})".format( |         return "SearchQuery({!r}, {!r}, {!r}, {!r}, {!r}, {!r}, {!r}, {!r}, {!r})".format( | ||||||
|             self.query, |             self.query, | ||||||
|             self.engineref_list, |             self.engineref_list, | ||||||
|             self.lang, |             self.lang, | ||||||
| @ -82,6 +85,7 @@ class SearchQuery: | |||||||
|             self.time_range, |             self.time_range, | ||||||
|             self.timeout_limit, |             self.timeout_limit, | ||||||
|             self.external_bang, |             self.external_bang, | ||||||
|  |             self.redirect_to_first_result, | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|     def __eq__(self, other): |     def __eq__(self, other): | ||||||
| @ -94,6 +98,7 @@ class SearchQuery: | |||||||
|             and self.time_range == other.time_range |             and self.time_range == other.time_range | ||||||
|             and self.timeout_limit == other.timeout_limit |             and self.timeout_limit == other.timeout_limit | ||||||
|             and self.external_bang == other.external_bang |             and self.external_bang == other.external_bang | ||||||
|  |             and self.redirect_to_first_result == other.redirect_to_first_result | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|     def __hash__(self): |     def __hash__(self): | ||||||
| @ -107,6 +112,7 @@ class SearchQuery: | |||||||
|                 self.time_range, |                 self.time_range, | ||||||
|                 self.timeout_limit, |                 self.timeout_limit, | ||||||
|                 self.external_bang, |                 self.external_bang, | ||||||
|  |                 self.redirect_to_first_result, | ||||||
|             ) |             ) | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
| @ -121,4 +127,5 @@ class SearchQuery: | |||||||
|             self.timeout_limit, |             self.timeout_limit, | ||||||
|             self.external_bang, |             self.external_bang, | ||||||
|             self.engine_data, |             self.engine_data, | ||||||
|  |             self.redirect_to_first_result, | ||||||
|         ) |         ) | ||||||
|  | |||||||
| @ -254,6 +254,7 @@ def get_search_query_from_webapp( | |||||||
|     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 | ||||||
|  |     redirect_to_first_result = raw_text_query.redirect_to_first_result | ||||||
|     engine_data = parse_engine_data(form) |     engine_data = parse_engine_data(form) | ||||||
| 
 | 
 | ||||||
|     query_lang = parse_lang(preferences, form, raw_text_query) |     query_lang = parse_lang(preferences, form, raw_text_query) | ||||||
| @ -288,6 +289,7 @@ def get_search_query_from_webapp( | |||||||
|             query_timeout, |             query_timeout, | ||||||
|             external_bang=external_bang, |             external_bang=external_bang, | ||||||
|             engine_data=engine_data, |             engine_data=engine_data, | ||||||
|  |             redirect_to_first_result=redirect_to_first_result, | ||||||
|         ), |         ), | ||||||
|         raw_text_query, |         raw_text_query, | ||||||
|         query_engineref_list_unknown, |         query_engineref_list_unknown, | ||||||
|  | |||||||
| @ -697,6 +697,10 @@ def search(): | |||||||
|     previous_result = None |     previous_result = None | ||||||
| 
 | 
 | ||||||
|     results = result_container.get_ordered_results() |     results = result_container.get_ordered_results() | ||||||
|  | 
 | ||||||
|  |     if search_query.redirect_to_first_result and results: | ||||||
|  |         return redirect(results[0]['url'], 302) | ||||||
|  | 
 | ||||||
|     for result in results: |     for result in results: | ||||||
|         if output_format == 'html': |         if output_format == 'html': | ||||||
|             if 'content' in result and result['content']: |             if 'content' in result and result['content']: | ||||||
|  | |||||||
| @ -225,18 +225,6 @@ class TestExternalBangParser(SearxTestCase): | |||||||
|         a = query.autocomplete_list[0] |         a = query.autocomplete_list[0] | ||||||
|         self.assertEqual(query.get_autocomplete_full_query(a), a + ' the query') |         self.assertEqual(query.get_autocomplete_full_query(a), a + ' the query') | ||||||
| 
 | 
 | ||||||
|     def test_external_bang_autocomplete_empty(self): |  | ||||||
|         query_text = 'the query !!' |  | ||||||
|         query = RawTextQuery(query_text, []) |  | ||||||
| 
 |  | ||||||
|         self.assertEqual(query.getFullQuery(), 'the query !!') |  | ||||||
|         self.assertEqual(len(query.query_parts), 0) |  | ||||||
|         self.assertFalse(query.specific) |  | ||||||
|         self.assertGreater(len(query.autocomplete_list), 2) |  | ||||||
| 
 |  | ||||||
|         a = query.autocomplete_list[0] |  | ||||||
|         self.assertEqual(query.get_autocomplete_full_query(a), 'the query ' + a) |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| class TestBang(SearxTestCase): | class TestBang(SearxTestCase): | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -27,7 +27,7 @@ class SearchQueryTestCase(SearxTestCase): | |||||||
|     def test_repr(self): |     def test_repr(self): | ||||||
|         s = SearchQuery('test', [EngineRef('bing', 'general')], 'all', 0, 1, '1', 5.0, 'g') |         s = SearchQuery('test', [EngineRef('bing', 'general')], 'all', 0, 1, '1', 5.0, 'g') | ||||||
|         self.assertEqual( |         self.assertEqual( | ||||||
|             repr(s), "SearchQuery('test', [EngineRef('bing', 'general')], 'all', 0, 1, '1', 5.0, 'g')" |             repr(s), "SearchQuery('test', [EngineRef('bing', 'general')], 'all', 0, 1, '1', 5.0, 'g', None)" | ||||||
|         )  # noqa |         )  # noqa | ||||||
| 
 | 
 | ||||||
|     def test_eq(self): |     def test_eq(self): | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Bnyro
						Bnyro