summaryrefslogtreecommitdiff
path: root/searx/query.py
diff options
context:
space:
mode:
authorJohannes 'josch' Schauer <josch@debian.org>2020-02-01 01:09:45 +0100
committerJohannes 'josch' Schauer <josch@debian.org>2020-02-01 01:09:45 +0100
commit3e49246c2e44159486ea66fed3757cdb4e4d0c50 (patch)
tree73fecfac5dd7475f346d4bff59d78aec04a966a8 /searx/query.py
Import Upstream version 0.15.0+dfsg1
Diffstat (limited to 'searx/query.py')
-rw-r--r--searx/query.py176
1 files changed, 176 insertions, 0 deletions
diff --git a/searx/query.py b/searx/query.py
new file mode 100644
index 0000000..0b5143d
--- /dev/null
+++ b/searx/query.py
@@ -0,0 +1,176 @@
+#!/usr/bin/env python
+
+'''
+searx is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+searx is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with searx. If not, see < http://www.gnu.org/licenses/ >.
+
+(C) 2014 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>
+'''
+
+from searx.languages import language_codes
+from searx.engines import (
+ categories, engines, engine_shortcuts
+)
+import re
+import sys
+
+if sys.version_info[0] == 3:
+ unicode = str
+
+VALID_LANGUAGE_CODE = re.compile(r'^[a-z]{2,3}(-[a-zA-Z]{2})?$')
+
+
+class RawTextQuery(object):
+ """parse raw text query (the value from the html input)"""
+
+ def __init__(self, query, disabled_engines):
+ self.query = query
+ self.disabled_engines = []
+
+ if disabled_engines:
+ self.disabled_engines = disabled_engines
+
+ self.query_parts = []
+ self.engines = []
+ self.languages = []
+ self.specific = False
+
+ # parse query, if tags are set, which
+ # change the serch engine or search-language
+ def parse_query(self):
+ self.query_parts = []
+
+ # split query, including whitespaces
+ raw_query_parts = re.split(r'(\s+)' if isinstance(self.query, str) else b'(\s+)', self.query)
+
+ parse_next = True
+
+ for query_part in raw_query_parts:
+ if not parse_next:
+ self.query_parts[-1] += query_part
+ continue
+
+ parse_next = False
+
+ # part does only contain spaces, skip
+ if query_part.isspace()\
+ or query_part == '':
+ parse_next = True
+ self.query_parts.append(query_part)
+ continue
+
+ # this force a language
+ if query_part[0] == ':':
+ lang = query_part[1:].lower().replace('_', '-')
+
+ # check if any language-code is equal with
+ # declared language-codes
+ for lc in language_codes:
+ lang_id, lang_name, country, english_name = map(unicode.lower, lc)
+
+ # if correct language-code is found
+ # set it as new search-language
+ if (lang == lang_id
+ or lang == lang_name
+ or lang == english_name
+ or lang.replace('-', ' ') == country)\
+ and lang not in self.languages:
+ parse_next = True
+ lang_parts = lang_id.split('-')
+ if len(lang_parts) == 2:
+ self.languages.append(lang_parts[0] + '-' + lang_parts[1].upper())
+ else:
+ self.languages.append(lang_id)
+ # to ensure best match (first match is not necessarily the best one)
+ if lang == lang_id:
+ break
+
+ # user may set a valid, yet not selectable language
+ if VALID_LANGUAGE_CODE.match(lang):
+ lang_parts = lang.split('-')
+ if len(lang_parts) > 1:
+ lang = lang_parts[0].lower() + '-' + lang_parts[1].upper()
+ if lang not in self.languages:
+ self.languages.append(lang)
+ parse_next = True
+
+ # this force a engine or category
+ if query_part[0] == '!' or query_part[0] == '?':
+ prefix = query_part[1:].replace('-', ' ').replace('_', ' ')
+
+ # check if prefix is equal with engine shortcut
+ if prefix in engine_shortcuts:
+ parse_next = True
+ engine_name = engine_shortcuts[prefix]
+ if engine_name in engines:
+ for engine_category in engines[engine_name].categories:
+ self.engines.append({'category': engine_category,
+ 'name': engine_name,
+ 'from_bang': True})
+
+ # check if prefix is equal with engine name
+ elif prefix in engines:
+ parse_next = True
+ if prefix in engines:
+ for engine_category in engines[prefix].categories:
+ self.engines.append({'category': engine_category,
+ 'name': prefix,
+ 'from_bang': True})
+
+ # check if prefix is equal with categorie name
+ elif prefix in categories:
+ # using all engines for that search, which
+ # are declared under that categorie name
+ parse_next = True
+ self.engines.extend({'category': prefix,
+ 'name': engine.name}
+ for engine in categories[prefix]
+ if (engine.name, prefix) not in self.disabled_engines)
+
+ if query_part[0] == '!':
+ self.specific = True
+
+ # append query part to query_part list
+ self.query_parts.append(query_part)
+
+ def changeSearchQuery(self, search_query):
+ if len(self.query_parts):
+ self.query_parts[-1] = search_query
+ else:
+ self.query_parts.append(search_query)
+
+ def getSearchQuery(self):
+ if len(self.query_parts):
+ return self.query_parts[-1]
+ else:
+ return ''
+
+ def getFullQuery(self):
+ # get full querry including whitespaces
+ return u''.join(self.query_parts)
+
+
+class SearchQuery(object):
+ """container for all the search parameters (query, language, etc...)"""
+
+ def __init__(self, query, engines, categories, lang, safesearch, pageno, time_range):
+ self.query = query.encode('utf-8')
+ self.engines = engines
+ self.categories = categories
+ self.lang = lang
+ self.safesearch = safesearch
+ self.pageno = pageno
+ self.time_range = time_range
+
+ def __str__(self):
+ return str(self.query) + ";" + str(self.engines)