mirror of
https://github.com/searxng/searxng.git
synced 2024-11-22 20:17:45 +01:00
commit
469e08881e
@ -35,9 +35,9 @@ def request(query, params):
|
|||||||
# get response from search-request
|
# get response from search-request
|
||||||
def response(resp):
|
def response(resp):
|
||||||
results = []
|
results = []
|
||||||
|
|
||||||
dom = html.fromstring(resp.text)
|
dom = html.fromstring(resp.text)
|
||||||
|
|
||||||
# parse results
|
# parse results
|
||||||
for result in dom.xpath('//div[@class="photo"]'):
|
for result in dom.xpath('//div[@class="photo"]'):
|
||||||
link = result.xpath('.//a')[0]
|
link = result.xpath('.//a')[0]
|
||||||
|
@ -81,7 +81,7 @@ def load_engine(engine_data):
|
|||||||
if engine_attr.startswith('_'):
|
if engine_attr.startswith('_'):
|
||||||
continue
|
continue
|
||||||
if getattr(engine, engine_attr) is None:
|
if getattr(engine, engine_attr) is None:
|
||||||
print('[E] Engine config error: Missing attribute "{0}.{1}"'\
|
print('[E] Engine config error: Missing attribute "{0}.{1}"'
|
||||||
.format(engine.name, engine_attr))
|
.format(engine.name, engine_attr))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
@ -102,7 +102,7 @@ def load_engine(engine_data):
|
|||||||
if engine.shortcut:
|
if engine.shortcut:
|
||||||
# TODO check duplications
|
# TODO check duplications
|
||||||
if engine.shortcut in engine_shortcuts:
|
if engine.shortcut in engine_shortcuts:
|
||||||
print('[E] Engine config error: ambigious shortcut: {0}'\
|
print('[E] Engine config error: ambigious shortcut: {0}'
|
||||||
.format(engine.shortcut))
|
.format(engine.shortcut))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
engine_shortcuts[engine.shortcut] = engine.name
|
engine_shortcuts[engine.shortcut] = engine.name
|
||||||
|
67
searx/engines/digg.py
Normal file
67
searx/engines/digg.py
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
## Digg (News, Social media)
|
||||||
|
#
|
||||||
|
# @website https://digg.com/
|
||||||
|
# @provide-api no
|
||||||
|
#
|
||||||
|
# @using-api no
|
||||||
|
# @results HTML (using search portal)
|
||||||
|
# @stable no (HTML can change)
|
||||||
|
# @parse url, title, content, publishedDate, thumbnail
|
||||||
|
|
||||||
|
from urllib import quote_plus
|
||||||
|
from json import loads
|
||||||
|
from lxml import html
|
||||||
|
from cgi import escape
|
||||||
|
from dateutil import parser
|
||||||
|
|
||||||
|
# engine dependent config
|
||||||
|
categories = ['news', 'social media']
|
||||||
|
paging = True
|
||||||
|
|
||||||
|
# search-url
|
||||||
|
base_url = 'https://digg.com/'
|
||||||
|
search_url = base_url+'api/search/{query}.json?position={position}&format=html'
|
||||||
|
|
||||||
|
# specific xpath variables
|
||||||
|
results_xpath = '//article'
|
||||||
|
link_xpath = './/small[@class="time"]//a'
|
||||||
|
title_xpath = './/h2//a//text()'
|
||||||
|
content_xpath = './/p//text()'
|
||||||
|
pubdate_xpath = './/time'
|
||||||
|
|
||||||
|
|
||||||
|
# do search-request
|
||||||
|
def request(query, params):
|
||||||
|
offset = (params['pageno'] - 1) * 10
|
||||||
|
params['url'] = search_url.format(position=offset,
|
||||||
|
query=quote_plus(query))
|
||||||
|
return params
|
||||||
|
|
||||||
|
|
||||||
|
# get response from search-request
|
||||||
|
def response(resp):
|
||||||
|
results = []
|
||||||
|
|
||||||
|
search_result = loads(resp.text)
|
||||||
|
|
||||||
|
dom = html.fromstring(search_result['html'])
|
||||||
|
|
||||||
|
# parse results
|
||||||
|
for result in dom.xpath(results_xpath):
|
||||||
|
url = result.attrib.get('data-contenturl')
|
||||||
|
thumbnail = result.xpath('.//img')[0].attrib.get('src')
|
||||||
|
title = ''.join(result.xpath(title_xpath))
|
||||||
|
content = escape(''.join(result.xpath(content_xpath)))
|
||||||
|
pubdate = result.xpath(pubdate_xpath)[0].attrib.get('datetime')
|
||||||
|
publishedDate = parser.parse(pubdate)
|
||||||
|
|
||||||
|
# append result
|
||||||
|
results.append({'url': url,
|
||||||
|
'title': title,
|
||||||
|
'content': content,
|
||||||
|
'template': 'videos.html',
|
||||||
|
'publishedDate': publishedDate,
|
||||||
|
'thumbnail': thumbnail})
|
||||||
|
|
||||||
|
# return results
|
||||||
|
return results
|
@ -53,7 +53,8 @@ def response(resp):
|
|||||||
|
|
||||||
for photo in photos:
|
for photo in photos:
|
||||||
|
|
||||||
# In paged configuration, the first pages' photos are represented by a None object
|
# In paged configuration, the first pages' photos
|
||||||
|
# are represented by a None object
|
||||||
if photo is None:
|
if photo is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@ -74,10 +75,15 @@ def response(resp):
|
|||||||
|
|
||||||
title = photo['title']
|
title = photo['title']
|
||||||
|
|
||||||
content = '<span class="photo-author">' + photo['owner']['username'] + '</span><br />'
|
content = '<span class="photo-author">' +\
|
||||||
|
photo['owner']['username'] +\
|
||||||
|
'</span><br />'
|
||||||
|
|
||||||
if 'description' in photo:
|
if 'description' in photo:
|
||||||
content = content + '<span class="description">' + photo['description'] + '</span>'
|
content = content +\
|
||||||
|
'<span class="description">' +\
|
||||||
|
photo['description'] +\
|
||||||
|
'</span>'
|
||||||
|
|
||||||
# append result
|
# append result
|
||||||
results.append({'url': url,
|
results.append({'url': url,
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
## Flickr (Images)
|
## Flickr (Images)
|
||||||
#
|
#
|
||||||
# @website https://www.flickr.com
|
# @website https://www.flickr.com
|
||||||
# @provide-api yes (https://secure.flickr.com/services/api/flickr.photos.search.html)
|
# @provide-api yes (https://secure.flickr.com/services/api/flickr.photos.search.html)
|
||||||
#
|
#
|
||||||
# @using-api yes
|
# @using-api yes
|
||||||
# @results JSON
|
# @results JSON
|
||||||
# @stable yes
|
# @stable yes
|
||||||
@ -18,16 +18,20 @@ categories = ['images']
|
|||||||
|
|
||||||
nb_per_page = 15
|
nb_per_page = 15
|
||||||
paging = True
|
paging = True
|
||||||
api_key= None
|
api_key = None
|
||||||
|
|
||||||
|
|
||||||
url = 'https://api.flickr.com/services/rest/?method=flickr.photos.search&api_key={api_key}&{text}&sort=relevance&extras=description%2C+owner_name%2C+url_o%2C+url_z&per_page={nb_per_page}&format=json&nojsoncallback=1&page={page}'
|
url = 'https://api.flickr.com/services/rest/?method=flickr.photos.search' +\
|
||||||
|
'&api_key={api_key}&{text}&sort=relevance' +\
|
||||||
|
'&extras=description%2C+owner_name%2C+url_o%2C+url_z' +\
|
||||||
|
'&per_page={nb_per_page}&format=json&nojsoncallback=1&page={page}'
|
||||||
photo_url = 'https://www.flickr.com/photos/{userid}/{photoid}'
|
photo_url = 'https://www.flickr.com/photos/{userid}/{photoid}'
|
||||||
|
|
||||||
paging = True
|
paging = True
|
||||||
|
|
||||||
|
|
||||||
def build_flickr_url(user_id, photo_id):
|
def build_flickr_url(user_id, photo_id):
|
||||||
return photo_url.format(userid=user_id,photoid=photo_id)
|
return photo_url.format(userid=user_id, photoid=photo_id)
|
||||||
|
|
||||||
|
|
||||||
def request(query, params):
|
def request(query, params):
|
||||||
@ -40,7 +44,7 @@ def request(query, params):
|
|||||||
|
|
||||||
def response(resp):
|
def response(resp):
|
||||||
results = []
|
results = []
|
||||||
|
|
||||||
search_results = loads(resp.text)
|
search_results = loads(resp.text)
|
||||||
|
|
||||||
# return empty array if there are no results
|
# return empty array if there are no results
|
||||||
@ -64,11 +68,14 @@ def response(resp):
|
|||||||
url = build_flickr_url(photo['owner'], photo['id'])
|
url = build_flickr_url(photo['owner'], photo['id'])
|
||||||
|
|
||||||
title = photo['title']
|
title = photo['title']
|
||||||
|
|
||||||
content = '<span class="photo-author">'+ photo['ownername'] +'</span><br />'
|
content = '<span class="photo-author">' +\
|
||||||
|
photo['ownername'] +\
|
||||||
content = content + '<span class="description">' + photo['description']['_content'] + '</span>'
|
'</span><br />' +\
|
||||||
|
'<span class="description">' +\
|
||||||
|
photo['description']['_content'] +\
|
||||||
|
'</span>'
|
||||||
|
|
||||||
# append result
|
# append result
|
||||||
results.append({'url': url,
|
results.append({'url': url,
|
||||||
'title': title,
|
'title': title,
|
||||||
|
@ -24,7 +24,7 @@ search_url = url + 'search/{search_term}/{pageno}/'
|
|||||||
|
|
||||||
# specific xpath variables
|
# specific xpath variables
|
||||||
magnet_xpath = './/a[@title="Torrent magnet link"]'
|
magnet_xpath = './/a[@title="Torrent magnet link"]'
|
||||||
#content_xpath = './/font[@class="detDesc"]//text()'
|
content_xpath = './/span[@class="font11px lightgrey block"]'
|
||||||
|
|
||||||
|
|
||||||
# do search-request
|
# do search-request
|
||||||
@ -56,7 +56,8 @@ def response(resp):
|
|||||||
link = result.xpath('.//a[@class="cellMainLink"]')[0]
|
link = result.xpath('.//a[@class="cellMainLink"]')[0]
|
||||||
href = urljoin(url, link.attrib['href'])
|
href = urljoin(url, link.attrib['href'])
|
||||||
title = ' '.join(link.xpath('.//text()'))
|
title = ' '.join(link.xpath('.//text()'))
|
||||||
content = escape(html.tostring(result.xpath('.//span[@class="font11px lightgrey block"]')[0], method="text"))
|
content = escape(html.tostring(result.xpath(content_xpath)[0],
|
||||||
|
method="text"))
|
||||||
seed = result.xpath('.//td[contains(@class, "green")]/text()')[0]
|
seed = result.xpath('.//td[contains(@class, "green")]/text()')[0]
|
||||||
leech = result.xpath('.//td[contains(@class, "red")]/text()')[0]
|
leech = result.xpath('.//td[contains(@class, "red")]/text()')[0]
|
||||||
|
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
from urllib import urlencode
|
from urllib import urlencode
|
||||||
from json import loads
|
from json import loads
|
||||||
import cgi
|
import cgi
|
||||||
import re
|
|
||||||
|
|
||||||
# engine dependent config
|
# engine dependent config
|
||||||
categories = ['it']
|
categories = ['it']
|
||||||
@ -33,7 +32,7 @@ def request(query, params):
|
|||||||
# get response from search-request
|
# get response from search-request
|
||||||
def response(resp):
|
def response(resp):
|
||||||
results = []
|
results = []
|
||||||
|
|
||||||
search_results = loads(resp.text)
|
search_results = loads(resp.text)
|
||||||
|
|
||||||
# parse results
|
# parse results
|
||||||
@ -41,21 +40,22 @@ def response(resp):
|
|||||||
href = result['url']
|
href = result['url']
|
||||||
title = "" + result['name'] + " - " + result['filename']
|
title = "" + result['name'] + " - " + result['filename']
|
||||||
content = result['repo'] + "<br />"
|
content = result['repo'] + "<br />"
|
||||||
|
|
||||||
lines = dict()
|
lines = dict()
|
||||||
for line, code in result['lines'].items():
|
for line, code in result['lines'].items():
|
||||||
lines[int(line)] = code
|
lines[int(line)] = code
|
||||||
|
|
||||||
content = content + '<pre class="code-formatter"><table class="code">'
|
content = content + '<pre class="code-formatter"><table class="code">'
|
||||||
for line, code in sorted(lines.items()):
|
for line, code in sorted(lines.items()):
|
||||||
content = content + '<tr><td class="line-number" style="padding-right:5px;">'
|
content = content + '<tr><td class="line-number" style="padding-right:5px;">'
|
||||||
content = content + str(line) + '</td><td class="code-snippet">'
|
content = content + str(line) + '</td><td class="code-snippet">'
|
||||||
# Replace every two spaces with ' &nbps;' to keep formatting while allowing the browser to break the line if necessary
|
# Replace every two spaces with ' &nbps;' to keep formatting
|
||||||
content = content + cgi.escape(code).replace('\t', ' ').replace(' ', ' ').replace(' ', ' ')
|
# while allowing the browser to break the line if necessary
|
||||||
|
content = content + cgi.escape(code).replace('\t', ' ').replace(' ', ' ').replace(' ', ' ')
|
||||||
content = content + "</td></tr>"
|
content = content + "</td></tr>"
|
||||||
|
|
||||||
content = content + "</table></pre>"
|
content = content + "</table></pre>"
|
||||||
|
|
||||||
# append result
|
# append result
|
||||||
results.append({'url': href,
|
results.append({'url': href,
|
||||||
'title': title,
|
'title': title,
|
||||||
|
@ -31,15 +31,22 @@ def request(query, params):
|
|||||||
# get response from search-request
|
# get response from search-request
|
||||||
def response(resp):
|
def response(resp):
|
||||||
results = []
|
results = []
|
||||||
|
|
||||||
search_results = loads(resp.text)
|
search_results = loads(resp.text)
|
||||||
|
|
||||||
# parse results
|
# parse results
|
||||||
for result in search_results['results']:
|
for result in search_results['results']:
|
||||||
href = result['url']
|
href = result['url']
|
||||||
title = "[" + result['type'] + "] " + result['namespace'] + " " + result['name']
|
title = "[" + result['type'] + "] " +\
|
||||||
content = '<span class="highlight">[' + result['type'] + "] " + result['name'] + " " + result['synopsis'] + "</span><br />" + result['description']
|
result['namespace'] +\
|
||||||
|
" " + result['name']
|
||||||
|
content = '<span class="highlight">[' +\
|
||||||
|
result['type'] + "] " +\
|
||||||
|
result['name'] + " " +\
|
||||||
|
result['synopsis'] +\
|
||||||
|
"</span><br />" +\
|
||||||
|
result['description']
|
||||||
|
|
||||||
# append result
|
# append result
|
||||||
results.append({'url': href,
|
results.append({'url': href,
|
||||||
'title': title,
|
'title': title,
|
||||||
|
@ -60,10 +60,14 @@ def response(resp):
|
|||||||
|
|
||||||
content = result.xpath('.//div[contains(@class,"red")]//text()')[0]
|
content = result.xpath('.//div[contains(@class,"red")]//text()')[0]
|
||||||
content = content + " - "
|
content = content + " - "
|
||||||
content = content + html.tostring(result.xpath('.//div[contains(@class,"grey-web")]')[0], method='text')
|
text = result.xpath('.//div[contains(@class,"grey-web")]')[0]
|
||||||
|
content = content + html.tostring(text, method='text')
|
||||||
|
|
||||||
if result.xpath(".//span") != []:
|
if result.xpath(".//span") != []:
|
||||||
content = content + " - (" + result.xpath(".//span//text()")[0].strip() + ")"
|
content = content +\
|
||||||
|
" - (" +\
|
||||||
|
result.xpath(".//span//text()")[0].strip() +\
|
||||||
|
")"
|
||||||
|
|
||||||
# append result
|
# append result
|
||||||
results.append({'url': href,
|
results.append({'url': href,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
## Twitter (Social media)
|
## Twitter (Social media)
|
||||||
#
|
#
|
||||||
# @website https://www.bing.com/news
|
# @website https://twitter.com/
|
||||||
# @provide-api yes (https://dev.twitter.com/docs/using-search)
|
# @provide-api yes (https://dev.twitter.com/docs/using-search)
|
||||||
#
|
#
|
||||||
# @using-api no
|
# @using-api no
|
||||||
@ -14,6 +14,7 @@ from urlparse import urljoin
|
|||||||
from urllib import urlencode
|
from urllib import urlencode
|
||||||
from lxml import html
|
from lxml import html
|
||||||
from cgi import escape
|
from cgi import escape
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
# engine dependent config
|
# engine dependent config
|
||||||
categories = ['social media']
|
categories = ['social media']
|
||||||
@ -27,7 +28,8 @@ search_url = base_url+'search?'
|
|||||||
results_xpath = '//li[@data-item-type="tweet"]'
|
results_xpath = '//li[@data-item-type="tweet"]'
|
||||||
link_xpath = './/small[@class="time"]//a'
|
link_xpath = './/small[@class="time"]//a'
|
||||||
title_xpath = './/span[@class="username js-action-profile-name"]//text()'
|
title_xpath = './/span[@class="username js-action-profile-name"]//text()'
|
||||||
content_xpath = './/p[@class="js-tweet-text tweet-text"]//text()'
|
content_xpath = './/p[@class="js-tweet-text tweet-text"]'
|
||||||
|
timestamp_xpath = './/span[contains(@class,"_timestamp")]'
|
||||||
|
|
||||||
|
|
||||||
# do search-request
|
# do search-request
|
||||||
@ -52,12 +54,21 @@ def response(resp):
|
|||||||
link = tweet.xpath(link_xpath)[0]
|
link = tweet.xpath(link_xpath)[0]
|
||||||
url = urljoin(base_url, link.attrib.get('href'))
|
url = urljoin(base_url, link.attrib.get('href'))
|
||||||
title = ''.join(tweet.xpath(title_xpath))
|
title = ''.join(tweet.xpath(title_xpath))
|
||||||
content = escape(''.join(tweet.xpath(content_xpath)))
|
content = escape(html.tostring(tweet.xpath(content_xpath)[0], method='text', encoding='UTF-8').decode("utf-8"))
|
||||||
|
pubdate = tweet.xpath(timestamp_xpath)
|
||||||
# append result
|
if len(pubdate) > 0:
|
||||||
results.append({'url': url,
|
timestamp = float(pubdate[0].attrib.get('data-time'))
|
||||||
'title': title,
|
publishedDate = datetime.fromtimestamp(timestamp, None)
|
||||||
'content': content})
|
# append result
|
||||||
|
results.append({'url': url,
|
||||||
|
'title': title,
|
||||||
|
'content': content,
|
||||||
|
'publishedDate': publishedDate})
|
||||||
|
else:
|
||||||
|
# append result
|
||||||
|
results.append({'url': url,
|
||||||
|
'title': title,
|
||||||
|
'content': content})
|
||||||
|
|
||||||
# return results
|
# return results
|
||||||
return results
|
return results
|
||||||
|
@ -154,7 +154,6 @@ def load_https_rules(rules_path):
|
|||||||
print(' * {n} https-rules loaded'.format(n=len(https_rules)))
|
print(' * {n} https-rules loaded'.format(n=len(https_rules)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def https_url_rewrite(result):
|
def https_url_rewrite(result):
|
||||||
skip_https_rewrite = False
|
skip_https_rewrite = False
|
||||||
# check if HTTPS rewrite is possible
|
# check if HTTPS rewrite is possible
|
||||||
|
@ -69,11 +69,16 @@ def threaded_requests(requests):
|
|||||||
print('engine timeout: {0}'.format(th._engine_name))
|
print('engine timeout: {0}'.format(th._engine_name))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# get default reqest parameter
|
# get default reqest parameter
|
||||||
def default_request_params():
|
def default_request_params():
|
||||||
return {
|
return {
|
||||||
'method': 'GET', 'headers': {}, 'data': {}, 'url': '', 'cookies': {}, 'verify': True}
|
'method': 'GET',
|
||||||
|
'headers': {},
|
||||||
|
'data': {},
|
||||||
|
'url': '',
|
||||||
|
'cookies': {},
|
||||||
|
'verify': True
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# create a callback wrapper for the search engine results
|
# create a callback wrapper for the search engine results
|
||||||
@ -487,14 +492,15 @@ class Search(object):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
# append request to list
|
# append request to list
|
||||||
requests.append((req, request_params['url'], request_args, selected_engine['name']))
|
requests.append((req, request_params['url'],
|
||||||
|
request_args,
|
||||||
|
selected_engine['name']))
|
||||||
|
|
||||||
if not requests:
|
if not requests:
|
||||||
return results, suggestions, answers, infoboxes
|
return results, suggestions, answers, infoboxes
|
||||||
# send all search-request
|
# send all search-request
|
||||||
threaded_requests(requests)
|
threaded_requests(requests)
|
||||||
|
|
||||||
|
|
||||||
while not results_queue.empty():
|
while not results_queue.empty():
|
||||||
engine_name, engine_results = results_queue.get_nowait()
|
engine_name, engine_results = results_queue.get_nowait()
|
||||||
|
|
||||||
|
@ -44,6 +44,10 @@ engines:
|
|||||||
- name : ddg definitions
|
- name : ddg definitions
|
||||||
engine : duckduckgo_definitions
|
engine : duckduckgo_definitions
|
||||||
shortcut : ddd
|
shortcut : ddd
|
||||||
|
|
||||||
|
- name : digg
|
||||||
|
engine : digg
|
||||||
|
shortcut : dg
|
||||||
|
|
||||||
- name : wikidata
|
- name : wikidata
|
||||||
engine : wikidata
|
engine : wikidata
|
||||||
@ -99,6 +103,33 @@ engines:
|
|||||||
engine : google_news
|
engine : google_news
|
||||||
shortcut : gon
|
shortcut : gon
|
||||||
|
|
||||||
|
- name : google play apps
|
||||||
|
engine : xpath
|
||||||
|
search_url : https://play.google.com/store/search?q={query}&c=apps
|
||||||
|
url_xpath : //a[@class="title"]/@href
|
||||||
|
title_xpath : //a[@class="title"]
|
||||||
|
content_xpath : //a[@class="subtitle"]
|
||||||
|
categories : files
|
||||||
|
shortcut : gpa
|
||||||
|
|
||||||
|
- name : google play movies
|
||||||
|
engine : xpath
|
||||||
|
search_url : https://play.google.com/store/search?q={query}&c=movies
|
||||||
|
url_xpath : //a[@class="title"]/@href
|
||||||
|
title_xpath : //a[@class="title"]
|
||||||
|
content_xpath : //a[@class="subtitle"]
|
||||||
|
categories : videos
|
||||||
|
shortcut : gpm
|
||||||
|
|
||||||
|
- name : google play music
|
||||||
|
engine : xpath
|
||||||
|
search_url : https://play.google.com/store/search?q={query}&c=music
|
||||||
|
url_xpath : //a[@class="title"]/@href
|
||||||
|
title_xpath : //a[@class="title"]
|
||||||
|
content_xpath : //a[@class="subtitle"]
|
||||||
|
categories : music
|
||||||
|
shortcut : gps
|
||||||
|
|
||||||
- name : openstreetmap
|
- name : openstreetmap
|
||||||
engine : openstreetmap
|
engine : openstreetmap
|
||||||
shortcut : osm
|
shortcut : osm
|
||||||
|
@ -30,8 +30,9 @@ def gen_useragent():
|
|||||||
|
|
||||||
|
|
||||||
def searx_useragent():
|
def searx_useragent():
|
||||||
return 'searx/{searx_version} {suffix}'.format(searx_version=VERSION_STRING,
|
return 'searx/{searx_version} {suffix}'.format(
|
||||||
suffix=settings['server'].get('useragent_suffix', ''))
|
searx_version=VERSION_STRING,
|
||||||
|
suffix=settings['server'].get('useragent_suffix', ''))
|
||||||
|
|
||||||
|
|
||||||
def highlight_content(content, query):
|
def highlight_content(content, query):
|
||||||
|
Loading…
Reference in New Issue
Block a user