Merge branch 'master' into fix-engine-spotify

This commit is contained in:
Markus Heiser 2019-12-29 09:47:06 +01:00 committed by GitHub
commit 36e72a4619
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
244 changed files with 10745 additions and 11499 deletions

View file

@ -1,14 +1,15 @@
{
"ua": "Mozilla/5.0 ({os}; rv:{version}) Gecko/20100101 Firefox/{version}",
"versions": [
"61.0.1",
"61.0",
"60.0.2",
"60.0.1",
"60.0"
"70.0.1",
"70.0",
"69.0.3",
"69.0.2",
"69.0.1",
"69.0"
],
"os": [
"Windows NT 10; WOW64",
"X11; Linux x86_64"
]
],
"ua": "Mozilla/5.0 ({os}; rv:{version}) Gecko/20100101 Firefox/{version}"
}

View file

@ -27,7 +27,7 @@ from json import loads
from requests import get
from searx import settings
from searx import logger
from searx.utils import load_module, match_language
from searx.utils import load_module, match_language, get_engine_from_settings
logger = logger.getChild('engines')
@ -53,7 +53,8 @@ engine_default_args = {'paging': False,
'disabled': False,
'suspend_end_time': 0,
'continuous_errors': 0,
'time_range_support': False}
'time_range_support': False,
'offline': False}
def load_engine(engine_data):
@ -128,14 +129,16 @@ def load_engine(engine_data):
engine.stats = {
'result_count': 0,
'search_count': 0,
'page_load_time': 0,
'page_load_count': 0,
'engine_time': 0,
'engine_time_count': 0,
'score_count': 0,
'errors': 0
}
if not engine.offline:
engine.stats['page_load_time'] = 0
engine.stats['page_load_count'] = 0
for category_name in engine.categories:
categories.setdefault(category_name, []).append(engine)
@ -173,11 +176,6 @@ def get_engines_stats():
results_num = \
engine.stats['result_count'] / float(engine.stats['search_count'])
if engine.stats['page_load_count'] != 0:
load_times = engine.stats['page_load_time'] / float(engine.stats['page_load_count']) # noqa
else:
load_times = 0
if engine.stats['engine_time_count'] != 0:
this_engine_time = engine.stats['engine_time'] / float(engine.stats['engine_time_count']) # noqa
else:
@ -189,14 +187,19 @@ def get_engines_stats():
else:
score = score_per_result = 0.0
max_pageload = max(load_times, max_pageload)
if not engine.offline:
load_times = 0
if engine.stats['page_load_count'] != 0:
load_times = engine.stats['page_load_time'] / float(engine.stats['page_load_count']) # noqa
max_pageload = max(load_times, max_pageload)
pageloads.append({'avg': load_times, 'name': engine.name})
max_engine_times = max(this_engine_time, max_engine_times)
max_results = max(results_num, max_results)
max_score = max(score, max_score)
max_score_per_result = max(score_per_result, max_score_per_result)
max_errors = max(max_errors, engine.stats['errors'])
pageloads.append({'avg': load_times, 'name': engine.name})
engine_times.append({'avg': this_engine_time, 'name': engine.name})
results.append({'avg': results_num, 'name': engine.name})
scores.append({'avg': score, 'name': engine.name})
@ -255,7 +258,7 @@ def initialize_engines(engine_list):
load_engines(engine_list)
def engine_init(engine_name, init_fn):
init_fn()
init_fn(get_engine_from_settings(engine_name))
logger.debug('%s engine: Initialized', engine_name)
for engine_name, engine in engines.items():

View file

@ -17,6 +17,7 @@ from searx.url_utils import urlencode
categories = ['science']
paging = True
base_url = 'http://export.arxiv.org/api/query?search_query=all:'\
+ '{query}&start={offset}&max_results={number_of_results}'
@ -29,7 +30,7 @@ def request(query, params):
# basic search
offset = (params['pageno'] - 1) * number_of_results
string_args = dict(query=query,
string_args = dict(query=query.decode('utf-8'),
offset=offset,
number_of_results=number_of_results)

View file

@ -13,10 +13,14 @@
@todo publishedDate
"""
import re
from lxml import html
from searx import logger, utils
from searx.engines.xpath import extract_text
from searx.url_utils import urlencode
from searx.utils import match_language, gen_useragent
from searx.utils import match_language, gen_useragent, eval_xpath
logger = logger.getChild('bing engine')
# engine dependent config
categories = ['general']
@ -30,9 +34,13 @@ base_url = 'https://www.bing.com/'
search_string = 'search?{query}&first={offset}'
def _get_offset_from_pageno(pageno):
return (pageno - 1) * 10 + 1
# do search-request
def request(query, params):
offset = (params['pageno'] - 1) * 10 + 1
offset = _get_offset_from_pageno(params.get('pageno', 0))
if params['language'] == 'all':
lang = 'EN'
@ -47,29 +55,21 @@ def request(query, params):
params['url'] = base_url + search_path
params['headers']['User-Agent'] = gen_useragent('Windows NT 6.3; WOW64')
return params
# get response from search-request
def response(resp):
results = []
result_len = 0
dom = html.fromstring(resp.text)
try:
results.append({'number_of_results': int(dom.xpath('//span[@class="sb_count"]/text()')[0]
.split()[0].replace(',', ''))})
except:
pass
# parse results
for result in dom.xpath('//div[@class="sa_cc"]'):
link = result.xpath('.//h3/a')[0]
for result in eval_xpath(dom, '//div[@class="sa_cc"]'):
link = eval_xpath(result, './/h3/a')[0]
url = link.attrib.get('href')
title = extract_text(link)
content = extract_text(result.xpath('.//p'))
content = extract_text(eval_xpath(result, './/p'))
# append result
results.append({'url': url,
@ -77,18 +77,35 @@ def response(resp):
'content': content})
# parse results again if nothing is found yet
for result in dom.xpath('//li[@class="b_algo"]'):
link = result.xpath('.//h2/a')[0]
for result in eval_xpath(dom, '//li[@class="b_algo"]'):
link = eval_xpath(result, './/h2/a')[0]
url = link.attrib.get('href')
title = extract_text(link)
content = extract_text(result.xpath('.//p'))
content = extract_text(eval_xpath(result, './/p'))
# append result
results.append({'url': url,
'title': title,
'content': content})
# return results
try:
result_len_container = "".join(eval_xpath(dom, '//span[@class="sb_count"]/text()'))
result_len_container = utils.to_string(result_len_container)
if "-" in result_len_container:
# Remove the part "from-to" for paginated request ...
result_len_container = result_len_container[result_len_container.find("-") * 2 + 2:]
result_len_container = re.sub('[^0-9]', '', result_len_container)
if len(result_len_container) > 0:
result_len = int(result_len_container)
except Exception as e:
logger.debug('result error :\n%s', e)
pass
if _get_offset_from_pageno(resp.search_params.get("pageno", 0)) > result_len:
return []
results.append({'number_of_results': result_len})
return results
@ -96,9 +113,9 @@ def response(resp):
def _fetch_supported_languages(resp):
supported_languages = []
dom = html.fromstring(resp.text)
options = dom.xpath('//div[@id="limit-languages"]//input')
options = eval_xpath(dom, '//div[@id="limit-languages"]//input')
for option in options:
code = option.xpath('./@id')[0].replace('_', '-')
code = eval_xpath(option, './@id')[0].replace('_', '-')
if code == 'nb':
code = 'no'
supported_languages.append(code)

View file

@ -15,7 +15,7 @@
from json import loads
from datetime import datetime
from searx.url_utils import urlencode
from searx.utils import match_language
from searx.utils import match_language, html_to_text
# engine dependent config
categories = ['videos']
@ -59,7 +59,7 @@ def response(resp):
for res in search_res['list']:
title = res['title']
url = res['url']
content = res['description']
content = html_to_text(res['description'])
thumbnail = res['thumbnail_360_url']
publishedDate = datetime.fromtimestamp(res['created_time'], None)
embedded = embedded_url.format(videoid=res['id'])

View file

@ -24,7 +24,7 @@ time_range_support = True
# search-url
base_url = 'https://www.deviantart.com/'
search_url = base_url + 'browse/all/?offset={offset}&{query}'
search_url = base_url + 'search?page={page}&{query}'
time_range_url = '&order={range}'
time_range_dict = {'day': 11,
@ -37,9 +37,7 @@ def request(query, params):
if params['time_range'] and params['time_range'] not in time_range_dict:
return params
offset = (params['pageno'] - 1) * 24
params['url'] = search_url.format(offset=offset,
params['url'] = search_url.format(page=params['pageno'],
query=urlencode({'q': query}))
if params['time_range'] in time_range_dict:
params['url'] += time_range_url.format(range=time_range_dict[params['time_range']])
@ -57,28 +55,27 @@ def response(resp):
dom = html.fromstring(resp.text)
regex = re.compile(r'\/200H\/')
# parse results
for result in dom.xpath('.//span[@class="thumb wide"]'):
link = result.xpath('.//a[@class="torpedo-thumb-link"]')[0]
url = link.attrib.get('href')
title = extract_text(result.xpath('.//span[@class="title"]'))
thumbnail_src = link.xpath('.//img')[0].attrib.get('src')
img_src = regex.sub('/', thumbnail_src)
for row in dom.xpath('//div[contains(@data-hook, "content_row")]'):
for result in row.xpath('./div'):
link = result.xpath('.//a[@data-hook="deviation_link"]')[0]
url = link.attrib.get('href')
title = link.attrib.get('title')
thumbnail_src = result.xpath('.//img')[0].attrib.get('src')
img_src = thumbnail_src
# http to https, remove domain sharding
thumbnail_src = re.sub(r"https?://(th|fc)\d+.", "https://th01.", thumbnail_src)
thumbnail_src = re.sub(r"http://", "https://", thumbnail_src)
# http to https, remove domain sharding
thumbnail_src = re.sub(r"https?://(th|fc)\d+.", "https://th01.", thumbnail_src)
thumbnail_src = re.sub(r"http://", "https://", thumbnail_src)
url = re.sub(r"http://(.*)\.deviantart\.com/", "https://\\1.deviantart.com/", url)
url = re.sub(r"http://(.*)\.deviantart\.com/", "https://\\1.deviantart.com/", url)
# append result
results.append({'url': url,
'title': title,
'img_src': img_src,
'thumbnail_src': thumbnail_src,
'template': 'images.html'})
# append result
results.append({'url': url,
'title': title,
'img_src': img_src,
'thumbnail_src': thumbnail_src,
'template': 'images.html'})
# return results
return results

View file

@ -11,11 +11,11 @@
import re
from lxml import html
from searx.utils import is_valid_lang
from searx.utils import is_valid_lang, eval_xpath
from searx.url_utils import urljoin
categories = ['general']
url = u'http://dictzone.com/{from_lang}-{to_lang}-dictionary/{query}'
url = u'https://dictzone.com/{from_lang}-{to_lang}-dictionary/{query}'
weight = 100
parser_re = re.compile(b'.*?([a-z]+)-([a-z]+) ([^ ]+)$', re.I)
@ -47,14 +47,14 @@ def response(resp):
dom = html.fromstring(resp.text)
for k, result in enumerate(dom.xpath(results_xpath)[1:]):
for k, result in enumerate(eval_xpath(dom, results_xpath)[1:]):
try:
from_result, to_results_raw = result.xpath('./td')
from_result, to_results_raw = eval_xpath(result, './td')
except:
continue
to_results = []
for to_result in to_results_raw.xpath('./p/a'):
for to_result in eval_xpath(to_results_raw, './p/a'):
t = to_result.text_content()
if t.strip():
to_results.append(to_result.text_content())

View file

@ -15,7 +15,8 @@ import string
from dateutil import parser
from json import loads
from lxml import html
from searx.url_utils import quote_plus
from searx.url_utils import urlencode
from datetime import datetime
# engine dependent config
categories = ['news', 'social media']
@ -23,7 +24,7 @@ paging = True
# search-url
base_url = 'https://digg.com/'
search_url = base_url + 'api/search/{query}.json?position={position}&format=html'
search_url = base_url + 'api/search/?{query}&from={position}&size=20&format=html'
# specific xpath variables
results_xpath = '//article'
@ -38,9 +39,9 @@ digg_cookie_chars = string.ascii_uppercase + string.ascii_lowercase +\
# do search-request
def request(query, params):
offset = (params['pageno'] - 1) * 10
offset = (params['pageno'] - 1) * 20
params['url'] = search_url.format(position=offset,
query=quote_plus(query))
query=urlencode({'q': query}))
params['cookies']['frontend.auid'] = ''.join(random.choice(
digg_cookie_chars) for _ in range(22))
return params
@ -52,30 +53,17 @@ def response(resp):
search_result = loads(resp.text)
if 'html' not in search_result or search_result['html'] == '':
return results
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 = ''.join(result.xpath(content_xpath))
pubdate = result.xpath(pubdate_xpath)[0].attrib.get('datetime')
publishedDate = parser.parse(pubdate)
# http to https
thumbnail = thumbnail.replace("http://static.digg.com", "https://static.digg.com")
for result in search_result['mapped']:
published = datetime.strptime(result['created']['ISO'], "%Y-%m-%d %H:%M:%S")
# append result
results.append({'url': url,
'title': title,
'content': content,
results.append({'url': result['url'],
'title': result['title'],
'content': result['excerpt'],
'template': 'videos.html',
'publishedDate': publishedDate,
'thumbnail': thumbnail})
'publishedDate': published,
'thumbnail': result['images']['thumbImage']})
# return results
return results

View file

@ -11,6 +11,7 @@
from lxml.html import fromstring
from searx.engines.xpath import extract_text
from searx.utils import eval_xpath
from searx.url_utils import urlencode
# engine dependent config
@ -45,16 +46,16 @@ def response(resp):
# parse results
# Quickhits
for r in doc.xpath('//div[@class="search_quickresult"]/ul/li'):
for r in eval_xpath(doc, '//div[@class="search_quickresult"]/ul/li'):
try:
res_url = r.xpath('.//a[@class="wikilink1"]/@href')[-1]
res_url = eval_xpath(r, './/a[@class="wikilink1"]/@href')[-1]
except:
continue
if not res_url:
continue
title = extract_text(r.xpath('.//a[@class="wikilink1"]/@title'))
title = extract_text(eval_xpath(r, './/a[@class="wikilink1"]/@title'))
# append result
results.append({'title': title,
@ -62,13 +63,13 @@ def response(resp):
'url': base_url + res_url})
# Search results
for r in doc.xpath('//dl[@class="search_results"]/*'):
for r in eval_xpath(doc, '//dl[@class="search_results"]/*'):
try:
if r.tag == "dt":
res_url = r.xpath('.//a[@class="wikilink1"]/@href')[-1]
title = extract_text(r.xpath('.//a[@class="wikilink1"]/@title'))
res_url = eval_xpath(r, './/a[@class="wikilink1"]/@href')[-1]
title = extract_text(eval_xpath(r, './/a[@class="wikilink1"]/@title'))
elif r.tag == "dd":
content = extract_text(r.xpath('.'))
content = extract_text(eval_xpath(r, '.'))
# append result
results.append({'title': title,

View file

@ -18,7 +18,7 @@ from json import loads
from searx.engines.xpath import extract_text
from searx.poolrequests import get
from searx.url_utils import urlencode
from searx.utils import match_language
from searx.utils import match_language, eval_xpath
# engine dependent config
categories = ['general']
@ -65,21 +65,36 @@ def get_region_code(lang, lang_list=[]):
def request(query, params):
if params['time_range'] and params['time_range'] not in time_range_dict:
if params['time_range'] not in (None, 'None', '') and params['time_range'] not in time_range_dict:
return params
offset = (params['pageno'] - 1) * 30
region_code = get_region_code(params['language'], supported_languages)
if region_code:
params['url'] = url.format(
query=urlencode({'q': query, 'kl': region_code}), offset=offset, dc_param=offset)
params['url'] = 'https://duckduckgo.com/html/'
if params['pageno'] > 1:
params['method'] = 'POST'
params['data']['q'] = query
params['data']['s'] = offset
params['data']['dc'] = 30
params['data']['nextParams'] = ''
params['data']['v'] = 'l'
params['data']['o'] = 'json'
params['data']['api'] = '/d.js'
if params['time_range'] in time_range_dict:
params['data']['df'] = time_range_dict[params['time_range']]
if region_code:
params['data']['kl'] = region_code
else:
params['url'] = url.format(
query=urlencode({'q': query}), offset=offset, dc_param=offset)
if region_code:
params['url'] = url.format(
query=urlencode({'q': query, 'kl': region_code}), offset=offset, dc_param=offset)
else:
params['url'] = url.format(
query=urlencode({'q': query}), offset=offset, dc_param=offset)
if params['time_range'] in time_range_dict:
params['url'] += time_range_url.format(range=time_range_dict[params['time_range']])
if params['time_range'] in time_range_dict:
params['url'] += time_range_url.format(range=time_range_dict[params['time_range']])
return params
@ -91,17 +106,19 @@ def response(resp):
doc = fromstring(resp.text)
# parse results
for r in doc.xpath(result_xpath):
for i, r in enumerate(eval_xpath(doc, result_xpath)):
if i >= 30:
break
try:
res_url = r.xpath(url_xpath)[-1]
res_url = eval_xpath(r, url_xpath)[-1]
except:
continue
if not res_url:
continue
title = extract_text(r.xpath(title_xpath))
content = extract_text(r.xpath(content_xpath))
title = extract_text(eval_xpath(r, title_xpath))
content = extract_text(eval_xpath(r, content_xpath))
# append result
results.append({'title': title,

View file

@ -1,3 +1,14 @@
"""
DuckDuckGo (definitions)
- `Instant Answer API`_
- `DuckDuckGo query`_
.. _Instant Answer API: https://duckduckgo.com/api
.. _DuckDuckGo query: https://api.duckduckgo.com/?q=DuckDuckGo&format=json&pretty=1
"""
import json
from lxml import html
from re import compile
@ -25,7 +36,8 @@ def result_to_text(url, text, htmlResult):
def request(query, params):
params['url'] = url.format(query=urlencode({'q': query}))
language = match_language(params['language'], supported_languages, language_aliases)
params['headers']['Accept-Language'] = language.split('-')[0]
language = language.split('-')[0]
params['headers']['Accept-Language'] = language
return params
@ -43,8 +55,9 @@ def response(resp):
# add answer if there is one
answer = search_res.get('Answer', '')
if answer != '':
results.append({'answer': html_to_text(answer)})
if answer:
if search_res.get('AnswerType', '') not in ['calc']:
results.append({'answer': html_to_text(answer)})
# add infobox
if 'Definition' in search_res:

View file

@ -11,6 +11,7 @@
from lxml import html, etree
import re
from searx.engines.xpath import extract_text
from searx.utils import eval_xpath
from searx.url_utils import quote, urljoin
from searx import logger
@ -52,9 +53,9 @@ def response(resp):
dom = html.fromstring(resp.text)
try:
number_of_results_string = re.sub('[^0-9]', '', dom.xpath(
'//a[@class="active" and contains(@href,"/suchen/dudenonline")]/span/text()')[0]
)
number_of_results_string =\
re.sub('[^0-9]', '',
eval_xpath(dom, '//a[@class="active" and contains(@href,"/suchen/dudenonline")]/span/text()')[0])
results.append({'number_of_results': int(number_of_results_string)})
@ -62,12 +63,12 @@ def response(resp):
logger.debug("Couldn't read number of results.")
pass
for result in dom.xpath('//section[not(contains(@class, "essay"))]'):
for result in eval_xpath(dom, '//section[not(contains(@class, "essay"))]'):
try:
url = result.xpath('.//h2/a')[0].get('href')
url = eval_xpath(result, './/h2/a')[0].get('href')
url = urljoin(base_url, url)
title = result.xpath('string(.//h2/a)').strip()
content = extract_text(result.xpath('.//p'))
title = eval_xpath(result, 'string(.//h2/a)').strip()
content = extract_text(eval_xpath(result, './/p'))
# append result
results.append({'url': url,
'title': title,

View file

@ -18,13 +18,13 @@ categories = ['files']
paging = True
# search-url
base_url = 'https://f-droid.org/'
search_url = base_url + 'repository/browse/?{query}'
base_url = 'https://search.f-droid.org/'
search_url = base_url + '?{query}'
# do search-request
def request(query, params):
query = urlencode({'fdfilter': query, 'fdpage': params['pageno']})
query = urlencode({'q': query, 'page': params['pageno'], 'lang': ''})
params['url'] = search_url.format(query=query)
return params
@ -35,17 +35,16 @@ def response(resp):
dom = html.fromstring(resp.text)
for app in dom.xpath('//div[@id="appheader"]'):
url = app.xpath('./ancestor::a/@href')[0]
title = app.xpath('./p/span/text()')[0]
img_src = app.xpath('.//img/@src')[0]
for app in dom.xpath('//a[@class="package-header"]'):
app_url = app.xpath('./@href')[0]
app_title = extract_text(app.xpath('./div/h4[@class="package-name"]/text()'))
app_content = extract_text(app.xpath('./div/div/span[@class="package-summary"]')).strip() \
+ ' - ' + extract_text(app.xpath('./div/div/span[@class="package-license"]')).strip()
app_img_src = app.xpath('./img[@class="package-icon"]/@src')[0]
content = extract_text(app.xpath('./p')[0])
content = content.replace(title, '', 1).strip()
results.append({'url': url,
'title': title,
'content': content,
'img_src': img_src})
results.append({'url': app_url,
'title': app_title,
'content': app_content,
'img_src': app_img_src})
return results

View file

@ -16,7 +16,8 @@ from json import loads
from time import time
import re
from searx.engines import logger
from searx.url_utils import urlencode, unquote
from searx.url_utils import urlencode
from searx.utils import ecma_unescape, html_to_text
logger = logger.getChild('flickr-noapi')
@ -75,11 +76,10 @@ def response(resp):
for index in legend:
photo = model_export['main'][index[0]][int(index[1])][index[2]][index[3]][int(index[4])]
author = unquote(photo.get('realname', ''))
source = unquote(photo.get('username', '')) + ' @ Flickr'
title = unquote(photo.get('title', ''))
content = unquote(photo.get('description', ''))
author = ecma_unescape(photo.get('realname', ''))
source = ecma_unescape(photo.get('username', '')) + ' @ Flickr'
title = ecma_unescape(photo.get('title', ''))
content = html_to_text(ecma_unescape(photo.get('description', '')))
img_src = None
# From the biggest to the lowest format
for image_size in image_sizes:

View file

@ -10,7 +10,10 @@
@parse url, title, content, thumbnail, img_src
"""
from cgi import escape
try:
from cgi import escape
except:
from html import escape
from lxml import html
from searx.engines.xpath import extract_text
from searx.url_utils import urljoin, urlencode

View file

@ -14,7 +14,9 @@ import random
from json import loads
from time import time
from lxml.html import fromstring
from searx.poolrequests import get
from searx.url_utils import urlencode
from searx.utils import eval_xpath
# engine dependent config
categories = ['general']
@ -30,13 +32,9 @@ search_string = 'search?{query}'\
'&c=main'\
'&s={offset}'\
'&format=json'\
'&qh=0'\
'&qlang={lang}'\
'&langcountry={lang}'\
'&ff={safesearch}'\
'&rxiec={rxieu}'\
'&ulse={ulse}'\
'&rand={rxikd}' # current unix timestamp
'&rand={rxikd}'
# specific xpath variables
results_xpath = '//response//result'
url_xpath = './/url'
@ -45,9 +43,26 @@ content_xpath = './/sum'
supported_languages_url = 'https://gigablast.com/search?&rxikd=1'
extra_param = '' # gigablast requires a random extra parameter
# which can be extracted from the source code of the search page
def parse_extra_param(text):
global extra_param
param_lines = [x for x in text.splitlines() if x.startswith('var url=') or x.startswith('url=url+')]
extra_param = ''
for l in param_lines:
extra_param += l.split("'")[1]
extra_param = extra_param.split('&')[-1]
def init(engine_settings=None):
parse_extra_param(get('http://gigablast.com/search?c=main&qlangcountry=en-us&q=south&s=10').text)
# do search-request
def request(query, params):
print("EXTRAPARAM:", extra_param)
offset = (params['pageno'] - 1) * number_of_results
if params['language'] == 'all':
@ -66,13 +81,11 @@ def request(query, params):
search_path = search_string.format(query=urlencode({'q': query}),
offset=offset,
number_of_results=number_of_results,
rxikd=int(time() * 1000),
rxieu=random.randint(1000000000, 9999999999),
ulse=random.randint(100000000, 999999999),
lang=language,
rxikd=int(time() * 1000),
safesearch=safesearch)
params['url'] = base_url + search_path
params['url'] = base_url + search_path + '&' + extra_param
return params
@ -82,7 +95,11 @@ def response(resp):
results = []
# parse results
response_json = loads(resp.text)
try:
response_json = loads(resp.text)
except:
parse_extra_param(resp.text)
raise Exception('extra param expired, please reload')
for result in response_json['results']:
# append result
@ -98,9 +115,9 @@ def response(resp):
def _fetch_supported_languages(resp):
supported_languages = []
dom = fromstring(resp.text)
links = dom.xpath('//span[@id="menu2"]/a')
links = eval_xpath(dom, '//span[@id="menu2"]/a')
for link in links:
href = link.xpath('./@href')[0].split('lang%3A')
href = eval_xpath(link, './@href')[0].split('lang%3A')
if len(href) == 2:
code = href[1].split('_')
if len(code) == 2:

View file

@ -14,7 +14,7 @@ from lxml import html, etree
from searx.engines.xpath import extract_text, extract_url
from searx import logger
from searx.url_utils import urlencode, urlparse, parse_qsl
from searx.utils import match_language
from searx.utils import match_language, eval_xpath
logger = logger.getChild('google engine')
@ -107,13 +107,12 @@ images_path = '/images'
supported_languages_url = 'https://www.google.com/preferences?#languages'
# specific xpath variables
results_xpath = '//div[@class="g"]'
url_xpath = './/h3/a/@href'
title_xpath = './/h3'
content_xpath = './/span[@class="st"]'
content_misc_xpath = './/div[@class="f slp"]'
suggestion_xpath = '//p[@class="_Bmc"]'
spelling_suggestion_xpath = '//a[@class="spell"]'
results_xpath = '//div[contains(@class, "ZINbbc")]'
url_xpath = './/div[@class="kCrYT"][1]/a/@href'
title_xpath = './/div[@class="kCrYT"][1]/a/div[1]'
content_xpath = './/div[@class="kCrYT"][2]//div[contains(@class, "BNeawe")]//div[contains(@class, "BNeawe")]'
suggestion_xpath = '//div[contains(@class, "ZINbbc")][last()]//div[@class="rVLSBd"]/a//div[contains(@class, "BNeawe")]'
spelling_suggestion_xpath = '//div[@id="scc"]//a'
# map : detail location
map_address_xpath = './/div[@class="s"]//table//td[2]/span/text()'
@ -156,7 +155,7 @@ def parse_url(url_string, google_hostname):
# returns extract_text on the first result selected by the xpath or None
def extract_text_from_dom(result, xpath):
r = result.xpath(xpath)
r = eval_xpath(result, xpath)
if len(r) > 0:
return extract_text(r[0])
return None
@ -199,9 +198,6 @@ def request(query, params):
params['headers']['Accept-Language'] = language + ',' + language + '-' + country
params['headers']['Accept'] = 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
# Force Internet Explorer 12 user agent to avoid loading the new UI that Searx can't parse
params['headers']['User-Agent'] = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)"
params['google_hostname'] = google_hostname
return params
@ -226,21 +222,21 @@ def response(resp):
# convert the text to dom
dom = html.fromstring(resp.text)
instant_answer = dom.xpath('//div[@id="_vBb"]//text()')
instant_answer = eval_xpath(dom, '//div[@id="_vBb"]//text()')
if instant_answer:
results.append({'answer': u' '.join(instant_answer)})
try:
results_num = int(dom.xpath('//div[@id="resultStats"]//text()')[0]
results_num = int(eval_xpath(dom, '//div[@id="resultStats"]//text()')[0]
.split()[1].replace(',', ''))
results.append({'number_of_results': results_num})
except:
pass
# parse results
for result in dom.xpath(results_xpath):
for result in eval_xpath(dom, results_xpath):
try:
title = extract_text(result.xpath(title_xpath)[0])
url = parse_url(extract_url(result.xpath(url_xpath), google_url), google_hostname)
title = extract_text(eval_xpath(result, title_xpath)[0])
url = parse_url(extract_url(eval_xpath(result, url_xpath), google_url), google_hostname)
parsed_url = urlparse(url, google_hostname)
# map result
@ -249,7 +245,7 @@ def response(resp):
continue
# if parsed_url.path.startswith(maps_path) or parsed_url.netloc.startswith(map_hostname_start):
# print "yooooo"*30
# x = result.xpath(map_near)
# x = eval_xpath(result, map_near)
# if len(x) > 0:
# # map : near the location
# results = results + parse_map_near(parsed_url, x, google_hostname)
@ -273,9 +269,7 @@ def response(resp):
content = extract_text_from_dom(result, content_xpath)
if content is None:
continue
content_misc = extract_text_from_dom(result, content_misc_xpath)
if content_misc is not None:
content = content_misc + "<br />" + content
# append result
results.append({'url': url,
'title': title,
@ -286,11 +280,11 @@ def response(resp):
continue
# parse suggestion
for suggestion in dom.xpath(suggestion_xpath):
for suggestion in eval_xpath(dom, suggestion_xpath):
# append suggestion
results.append({'suggestion': extract_text(suggestion)})
for correction in dom.xpath(spelling_suggestion_xpath):
for correction in eval_xpath(dom, spelling_suggestion_xpath):
results.append({'correction': extract_text(correction)})
# return results
@ -299,9 +293,9 @@ def response(resp):
def parse_images(result, google_hostname):
results = []
for image in result.xpath(images_xpath):
url = parse_url(extract_text(image.xpath(image_url_xpath)[0]), google_hostname)
img_src = extract_text(image.xpath(image_img_src_xpath)[0])
for image in eval_xpath(result, images_xpath):
url = parse_url(extract_text(eval_xpath(image, image_url_xpath)[0]), google_hostname)
img_src = extract_text(eval_xpath(image, image_img_src_xpath)[0])
# append result
results.append({'url': url,
@ -388,10 +382,10 @@ def attributes_to_html(attributes):
def _fetch_supported_languages(resp):
supported_languages = {}
dom = html.fromstring(resp.text)
options = dom.xpath('//*[@id="langSec"]//input[@name="lr"]')
options = eval_xpath(dom, '//*[@id="langSec"]//input[@name="lr"]')
for option in options:
code = option.xpath('./@value')[0].split('_')[-1]
name = option.xpath('./@data-name')[0].title()
code = eval_xpath(option, './@value')[0].split('_')[-1]
name = eval_xpath(option, './@data-name')[0].title()
supported_languages[code] = {"name": name}
return supported_languages

View file

@ -70,11 +70,21 @@ def response(resp):
try:
metadata = loads(result)
img_format = "{0} {1}x{2}".format(metadata['ity'], str(metadata['ow']), str(metadata['oh']))
source = "{0} ({1})".format(metadata['st'], metadata['isu'])
img_format = metadata.get('ity', '')
img_width = metadata.get('ow', '')
img_height = metadata.get('oh', '')
if img_width and img_height:
img_format += " {0}x{1}".format(img_width, img_height)
source = metadata.get('st', '')
source_url = metadata.get('isu', '')
if source_url:
source += " ({0})".format(source_url)
results.append({'url': metadata['ru'],
'title': metadata['pt'],
'content': metadata['s'],
'content': metadata.get('s', ''),
'source': source,
'img_format': img_format,
'thumbnail_src': metadata['tu'],

View file

@ -75,15 +75,17 @@ def response(resp):
# get thumbnails
script = str(dom.xpath('//script[contains(., "_setImagesSrc")]')[0].text)
id = result.xpath('.//div[@class="s"]//img/@id')[0]
thumbnails_data = re.findall('s=\'(.*?)(?:\\\\[a-z,1-9,\\\\]+\'|\')\;var ii=\[(?:|[\'vidthumb\d+\',]+)\'' + id,
script)
tmp = []
if len(thumbnails_data) != 0:
tmp = re.findall('(data:image/jpeg;base64,[a-z,A-Z,0-9,/,\+]+)', thumbnails_data[0])
thumbnail = ''
if len(tmp) != 0:
thumbnail = tmp[-1]
ids = result.xpath('.//div[@class="s"]//img/@id')
if len(ids) > 0:
thumbnails_data = \
re.findall('s=\'(.*?)(?:\\\\[a-z,1-9,\\\\]+\'|\')\;var ii=\[(?:|[\'vidthumb\d+\',]+)\'' + ids[0],
script)
tmp = []
if len(thumbnails_data) != 0:
tmp = re.findall('(data:image/jpeg;base64,[a-z,A-Z,0-9,/,\+]+)', thumbnails_data[0])
thumbnail = ''
if len(tmp) != 0:
thumbnail = tmp[-1]
# append result
results.append({'url': url,

100
searx/engines/invidious.py Normal file
View file

@ -0,0 +1,100 @@
# Invidious (Videos)
#
# @website https://invidio.us/
# @provide-api yes (https://github.com/omarroth/invidious/wiki/API)
#
# @using-api yes
# @results JSON
# @stable yes
# @parse url, title, content, publishedDate, thumbnail, embedded
from searx.url_utils import quote_plus
from dateutil import parser
import time
# engine dependent config
categories = ["videos", "music"]
paging = True
language_support = True
time_range_support = True
# search-url
base_url = "https://invidio.us/"
# do search-request
def request(query, params):
time_range_dict = {
"day": "today",
"week": "week",
"month": "month",
"year": "year",
}
search_url = base_url + "api/v1/search?q={query}"
params["url"] = search_url.format(
query=quote_plus(query)
) + "&page={pageno}".format(pageno=params["pageno"])
if params["time_range"] in time_range_dict:
params["url"] += "&date={timerange}".format(
timerange=time_range_dict[params["time_range"]]
)
if params["language"] != "all":
lang = params["language"].split("-")
if len(lang) == 2:
params["url"] += "&range={lrange}".format(lrange=lang[1])
return params
# get response from search-request
def response(resp):
results = []
search_results = resp.json()
embedded_url = (
'<iframe width="540" height="304" '
+ 'data-src="'
+ base_url
+ 'embed/{videoid}" '
+ 'frameborder="0" allowfullscreen></iframe>'
)
base_invidious_url = base_url + "watch?v="
for result in search_results:
rtype = result.get("type", None)
if rtype == "video":
videoid = result.get("videoId", None)
if not videoid:
continue
url = base_invidious_url + videoid
embedded = embedded_url.format(videoid=videoid)
thumbs = result.get("videoThumbnails", [])
thumb = next(
(th for th in thumbs if th["quality"] == "sddefault"), None
)
if thumb:
thumbnail = thumb.get("url", "")
else:
thumbnail = ""
publishedDate = parser.parse(
time.ctime(result.get("published", 0))
)
results.append(
{
"url": url,
"title": result.get("title", ""),
"content": result.get("description", ""),
"template": "videos.html",
"publishedDate": publishedDate,
"embedded": embedded,
"thumbnail": thumbnail,
}
)
return results

View file

@ -24,7 +24,7 @@ result_base_url = 'https://openstreetmap.org/{osm_type}/{osm_id}'
# do search-request
def request(query, params):
params['url'] = base_url + search_string.format(query=query)
params['url'] = base_url + search_string.format(query=query.decode('utf-8'))
return params

View file

@ -50,6 +50,7 @@ def request(query, params):
language = match_language(params['language'], supported_languages, language_aliases)
params['url'] += '&locale=' + language.replace('-', '_').lower()
params['headers']['User-Agent'] = 'Mozilla/5.0 (X11; Linux x86_64; rv:69.0) Gecko/20100101 Firefox/69.0'
return params

78
searx/engines/seedpeer.py Normal file
View file

@ -0,0 +1,78 @@
# Seedpeer (Videos, Music, Files)
#
# @website https://seedpeer.me
# @provide-api no (nothing found)
#
# @using-api no
# @results HTML (using search portal)
# @stable yes (HTML can change)
# @parse url, title, content, seed, leech, magnetlink
from lxml import html
from json import loads
from operator import itemgetter
from searx.url_utils import quote, urljoin
from searx.engines.xpath import extract_text
url = 'https://seedpeer.me/'
search_url = url + 'search/{search_term}?page={page_no}'
torrent_file_url = url + 'torrent/{torrent_hash}'
# specific xpath variables
script_xpath = '//script[@type="text/javascript"][not(@src)]'
torrent_xpath = '(//table)[2]/tbody/tr'
link_xpath = '(./td)[1]/a/@href'
age_xpath = '(./td)[2]'
size_xpath = '(./td)[3]'
# do search-request
def request(query, params):
params['url'] = search_url.format(search_term=quote(query),
page_no=params['pageno'])
return params
# get response from search-request
def response(resp):
results = []
dom = html.fromstring(resp.text)
result_rows = dom.xpath(torrent_xpath)
try:
script_element = dom.xpath(script_xpath)[0]
json_string = script_element.text[script_element.text.find('{'):]
torrents_json = loads(json_string)
except:
return []
# parse results
for torrent_row, torrent_json in zip(result_rows, torrents_json['data']['list']):
title = torrent_json['name']
seed = int(torrent_json['seeds'])
leech = int(torrent_json['peers'])
size = int(torrent_json['size'])
torrent_hash = torrent_json['hash']
torrentfile = torrent_file_url.format(torrent_hash=torrent_hash)
magnetlink = 'magnet:?xt=urn:btih:{}'.format(torrent_hash)
age = extract_text(torrent_row.xpath(age_xpath))
link = torrent_row.xpath(link_xpath)[0]
href = urljoin(url, link)
# append result
results.append({'url': href,
'title': title,
'content': age,
'seed': seed,
'leech': leech,
'filesize': size,
'torrentfile': torrentfile,
'magnetlink': magnetlink,
'template': 'torrent.html'})
# return results sorted by seeder
return sorted(results, key=itemgetter('seed'), reverse=True)

View file

@ -51,7 +51,9 @@ def get_client_id():
if response.ok:
tree = html.fromstring(response.content)
script_tags = tree.xpath("//script[contains(@src, '/assets/app')]")
# script_tags has been moved from /assets/app/ to /assets/ path. I
# found client_id in https://a-v2.sndcdn.com/assets/49-a0c01933-3.js
script_tags = tree.xpath("//script[contains(@src, '/assets/')]")
app_js_urls = [script_tag.get('src') for script_tag in script_tags if script_tag is not None]
# extracts valid app_js urls from soundcloud.com content
@ -66,7 +68,7 @@ def get_client_id():
return ""
def init():
def init(engine_settings=None):
global guest_client_id
# api-key
guest_client_id = get_client_id()

View file

@ -15,6 +15,8 @@ from dateutil import parser
from datetime import datetime, timedelta
import re
from searx.engines.xpath import extract_text
from searx.languages import language_codes
from searx.utils import eval_xpath
# engine dependent config
categories = ['general']
@ -22,7 +24,7 @@ categories = ['general']
# (probably the parameter qid), require
# storing of qid's between mulitble search-calls
# paging = False
paging = True
language_support = True
# search-url
@ -32,23 +34,32 @@ search_url = base_url + 'do/search'
# specific xpath variables
# ads xpath //div[@id="results"]/div[@id="sponsored"]//div[@class="result"]
# not ads: div[@class="result"] are the direct childs of div[@id="results"]
results_xpath = '//li[contains(@class, "search-result") and contains(@class, "search-item")]'
link_xpath = './/h3/a'
content_xpath = './p[@class="search-item__body"]'
results_xpath = '//div[@class="w-gl__result"]'
link_xpath = './/a[@class="w-gl__result-title"]'
content_xpath = './/p[@class="w-gl__description"]'
# do search-request
def request(query, params):
offset = (params['pageno'] - 1) * 10
params['url'] = search_url
params['method'] = 'POST'
params['data'] = {'query': query,
'startat': offset}
params['data'] = {
'query': query,
'page': params['pageno'],
'cat': 'web',
'cmd': 'process_search',
'engine0': 'v1all',
}
# set language if specified
if params['language'] != 'all':
params['data']['with_language'] = ('lang_' + params['language'].split('-')[0])
language = 'english'
for lc, _, _, lang in language_codes:
if lc == params['language']:
language = lang
params['data']['language'] = language
params['data']['lui'] = language
return params
@ -60,8 +71,8 @@ def response(resp):
dom = html.fromstring(resp.text)
# parse results
for result in dom.xpath(results_xpath):
links = result.xpath(link_xpath)
for result in eval_xpath(dom, results_xpath):
links = eval_xpath(result, link_xpath)
if not links:
continue
link = links[0]
@ -77,8 +88,8 @@ def response(resp):
title = extract_text(link)
if result.xpath(content_xpath):
content = extract_text(result.xpath(content_xpath))
if eval_xpath(result, content_xpath):
content = extract_text(eval_xpath(result, content_xpath))
else:
content = ''

View file

@ -16,7 +16,7 @@ from searx.poolrequests import get
from searx.engines.xpath import extract_text
from searx.engines.wikipedia import _fetch_supported_languages, supported_languages_url
from searx.url_utils import urlencode
from searx.utils import match_language
from searx.utils import match_language, eval_xpath
from json import loads
from lxml.html import fromstring
@ -57,22 +57,6 @@ language_fallback_xpath = '//sup[contains(@class,"wb-language-fallback-indicator
calendar_name_xpath = './/sup[contains(@class,"wb-calendar-name")]'
media_xpath = value_xpath + '//div[contains(@class,"commons-media-caption")]//a'
# xpath_cache
xpath_cache = {}
def get_xpath(xpath_str):
result = xpath_cache.get(xpath_str, None)
if not result:
result = etree.XPath(xpath_str)
xpath_cache[xpath_str] = result
return result
def eval_xpath(element, xpath_str):
xpath = get_xpath(xpath_str)
return xpath(element)
def get_id_cache(result):
id_cache = {}

View file

@ -21,7 +21,8 @@ search_url = base_url + u'w/api.php?'\
'action=query'\
'&format=json'\
'&{query}'\
'&prop=extracts|pageimages'\
'&prop=extracts|pageimages|pageprops'\
'&ppprop=disambiguation'\
'&exintro'\
'&explaintext'\
'&pithumbsize=300'\
@ -79,12 +80,15 @@ def response(resp):
# wikipedia article's unique id
# first valid id is assumed to be the requested article
if 'pages' not in search_result['query']:
return results
for article_id in search_result['query']['pages']:
page = search_result['query']['pages'][article_id]
if int(article_id) > 0:
break
if int(article_id) < 0:
if int(article_id) < 0 or 'disambiguation' in page.get('pageprops', {}):
return []
title = page.get('title')
@ -96,6 +100,7 @@ def response(resp):
extract = page.get('extract')
summary = extract_first_paragraph(extract, title, image)
summary = summary.replace('() ', '')
# link to wikipedia article
wikipedia_link = base_url.format(language=url_lang(resp.search_params['language'])) \

View file

@ -55,7 +55,7 @@ def obtain_token():
return token
def init():
def init(engine_settings=None):
obtain_token()

View file

@ -11,8 +11,8 @@
"""
from lxml import html
import re
from searx.url_utils import urlencode, urljoin
from searx.engines.xpath import extract_text
# engine dependent config
categories = ['images']
@ -34,41 +34,18 @@ def request(query, params):
def response(resp):
results = []
# get links from result-text
regex = re.compile('(</a>|<a)')
results_parts = re.split(regex, resp.text)
cur_element = ''
# iterate over link parts
for result_part in results_parts:
dom = html.fromstring(resp.text)
for res in dom.xpath('//div[@class="List-item MainListing"]'):
# processed start and end of link
if result_part == '<a':
cur_element = result_part
continue
elif result_part != '</a>':
cur_element += result_part
continue
cur_element += result_part
# fix xml-error
cur_element = cur_element.replace('"></a>', '"/></a>')
dom = html.fromstring(cur_element)
link = dom.xpath('//a')[0]
link = res.xpath('//a')[0]
url = urljoin(base_url, link.attrib.get('href'))
title = link.attrib.get('title', '')
title = extract_text(link)
thumbnail_src = urljoin(base_url, link.xpath('.//img')[0].attrib['src'])
thumbnail_src = urljoin(base_url, res.xpath('.//img')[0].attrib['src'])
# TODO: get image with higher resolution
img_src = thumbnail_src
# check if url is showing to a photo
if '/photo/' not in url:
continue
# append result
results.append({'url': url,
'title': title,

View file

@ -1,6 +1,6 @@
from lxml import html
from lxml.etree import _ElementStringResult, _ElementUnicodeResult
from searx.utils import html_to_text
from searx.utils import html_to_text, eval_xpath
from searx.url_utils import unquote, urlencode, urljoin, urlparse
search_url = None
@ -104,15 +104,15 @@ def response(resp):
results = []
dom = html.fromstring(resp.text)
if results_xpath:
for result in dom.xpath(results_xpath):
url = extract_url(result.xpath(url_xpath), search_url)
title = extract_text(result.xpath(title_xpath))
content = extract_text(result.xpath(content_xpath))
for result in eval_xpath(dom, results_xpath):
url = extract_url(eval_xpath(result, url_xpath), search_url)
title = extract_text(eval_xpath(result, title_xpath))
content = extract_text(eval_xpath(result, content_xpath))
tmp_result = {'url': url, 'title': title, 'content': content}
# add thumbnail if available
if thumbnail_xpath:
thumbnail_xpath_result = result.xpath(thumbnail_xpath)
thumbnail_xpath_result = eval_xpath(result, thumbnail_xpath)
if len(thumbnail_xpath_result) > 0:
tmp_result['img_src'] = extract_url(thumbnail_xpath_result, search_url)
@ -120,14 +120,14 @@ def response(resp):
else:
for url, title, content in zip(
(extract_url(x, search_url) for
x in dom.xpath(url_xpath)),
map(extract_text, dom.xpath(title_xpath)),
map(extract_text, dom.xpath(content_xpath))
x in eval_xpath(dom, url_xpath)),
map(extract_text, eval_xpath(dom, title_xpath)),
map(extract_text, eval_xpath(dom, content_xpath))
):
results.append({'url': url, 'title': title, 'content': content})
if not suggestion_xpath:
return results
for suggestion in dom.xpath(suggestion_xpath):
for suggestion in eval_xpath(dom, suggestion_xpath):
results.append({'suggestion': extract_text(suggestion)})
return results

View file

@ -14,7 +14,7 @@
from lxml import html
from searx.engines.xpath import extract_text, extract_url
from searx.url_utils import unquote, urlencode
from searx.utils import match_language
from searx.utils import match_language, eval_xpath
# engine dependent config
categories = ['general']
@ -109,21 +109,21 @@ def response(resp):
dom = html.fromstring(resp.text)
try:
results_num = int(dom.xpath('//div[@class="compPagination"]/span[last()]/text()')[0]
results_num = int(eval_xpath(dom, '//div[@class="compPagination"]/span[last()]/text()')[0]
.split()[0].replace(',', ''))
results.append({'number_of_results': results_num})
except:
pass
# parse results
for result in dom.xpath(results_xpath):
for result in eval_xpath(dom, results_xpath):
try:
url = parse_url(extract_url(result.xpath(url_xpath), search_url))
title = extract_text(result.xpath(title_xpath)[0])
url = parse_url(extract_url(eval_xpath(result, url_xpath), search_url))
title = extract_text(eval_xpath(result, title_xpath)[0])
except:
continue
content = extract_text(result.xpath(content_xpath)[0])
content = extract_text(eval_xpath(result, content_xpath)[0])
# append result
results.append({'url': url,
@ -131,7 +131,7 @@ def response(resp):
'content': content})
# if no suggestion found, return results
suggestions = dom.xpath(suggestion_xpath)
suggestions = eval_xpath(dom, suggestion_xpath)
if not suggestions:
return results
@ -148,9 +148,9 @@ def response(resp):
def _fetch_supported_languages(resp):
supported_languages = []
dom = html.fromstring(resp.text)
options = dom.xpath('//div[@id="yschlang"]/span/label/input')
options = eval_xpath(dom, '//div[@id="yschlang"]/span/label/input')
for option in options:
code_parts = option.xpath('./@value')[0][5:].split('_')
code_parts = eval_xpath(option, './@value')[0][5:].split('_')
if len(code_parts) == 2:
code = code_parts[0] + '-' + code_parts[1].upper()
else:

View file

@ -67,12 +67,8 @@ def response(resp):
if videoid is not None:
url = base_youtube_url + videoid
thumbnail = 'https://i.ytimg.com/vi/' + videoid + '/hqdefault.jpg'
title = video.get('title', {}).get('simpleText', videoid)
description_snippet = video.get('descriptionSnippet', {})
if 'runs' in description_snippet:
content = reduce(lambda a, b: a + b.get('text', ''), description_snippet.get('runs'), '')
else:
content = description_snippet.get('simpleText', '')
title = get_text_from_json(video.get('title', {}))
content = get_text_from_json(video.get('descriptionSnippet', {}))
embedded = embedded_url.format(videoid=videoid)
# append result
@ -85,3 +81,10 @@ def response(resp):
# return results
return results
def get_text_from_json(element):
if 'runs' in element:
return reduce(lambda a, b: a + b.get('text', ''), element.get('runs'), '')
else:
return element.get('simpleText', '')

View file

@ -28,5 +28,6 @@ class SearxParameterException(SearxException):
else:
message = 'Invalid value "' + value + '" for parameter ' + name
super(SearxParameterException, self).__init__(message)
self.message = message
self.parameter_name = name
self.parameter_value = value

View file

@ -225,6 +225,9 @@ def https_url_rewrite(result):
def on_result(request, search, result):
if 'parsed_url' not in result:
return True
if result['parsed_url'].scheme == 'http':
https_url_rewrite(result)
return True

View file

@ -35,6 +35,9 @@ def get_doi_resolver(args, preference_doi_resolver):
def on_result(request, search, result):
if 'parsed_url' not in result:
return True
doi = extract_doi(result['parsed_url'])
if doi and len(doi) < 50:
for suffix in ('/', '.pdf', '/full', '/meta', '/abstract'):

View file

@ -17,10 +17,10 @@ along with searx. If not, see < http://www.gnu.org/licenses/ >.
from flask_babel import gettext
import re
from searx.url_utils import urlunparse
from searx.url_utils import urlunparse, parse_qsl, urlencode
regexes = {re.compile(r'utm_[^&]+&?'),
re.compile(r'(wkey|wemail)[^&]+&?'),
regexes = {re.compile(r'utm_[^&]+'),
re.compile(r'(wkey|wemail)[^&]*'),
re.compile(r'&$')}
name = gettext('Tracker URL remover')
@ -30,16 +30,23 @@ preference_section = 'privacy'
def on_result(request, search, result):
if 'parsed_url' not in result:
return True
query = result['parsed_url'].query
if query == "":
return True
parsed_query = parse_qsl(query)
for reg in regexes:
query = reg.sub('', query)
if query != result['parsed_url'].query:
result['parsed_url'] = result['parsed_url']._replace(query=query)
result['url'] = urlunparse(result['parsed_url'])
changes = 0
for i, (param_name, _) in enumerate(list(parsed_query)):
for reg in regexes:
if reg.match(param_name):
parsed_query.pop(i - changes)
changes += 1
result['parsed_url'] = result['parsed_url']._replace(query=urlencode(parsed_query))
result['url'] = urlunparse(result['parsed_url'])
break
return True

View file

@ -43,6 +43,7 @@ class RawTextQuery(object):
self.query_parts = []
self.engines = []
self.languages = []
self.timeout_limit = None
self.specific = False
# parse query, if tags are set, which
@ -69,6 +70,21 @@ class RawTextQuery(object):
self.query_parts.append(query_part)
continue
# this force the timeout
if query_part[0] == '<':
try:
raw_timeout_limit = int(query_part[1:])
if raw_timeout_limit < 100:
# below 100, the unit is the second ( <3 = 3 seconds timeout )
self.timeout_limit = float(raw_timeout_limit)
else:
# 100 or above, the unit is the millisecond ( <850 = 850 milliseconds timeout )
self.timeout_limit = raw_timeout_limit / 1000.0
parse_next = True
except ValueError:
# error not reported to the user
pass
# this force a language
if query_part[0] == ':':
lang = query_part[1:].lower().replace('_', '-')
@ -161,14 +177,15 @@ class RawTextQuery(object):
class SearchQuery(object):
"""container for all the search parameters (query, language, etc...)"""
def __init__(self, query, engines, categories, lang, safesearch, pageno, time_range):
def __init__(self, query, engines, categories, lang, safesearch, pageno, time_range, timeout_limit=None):
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
self.time_range = None if time_range in ('', 'None', None) else time_range
self.timeout_limit = timeout_limit
def __str__(self):
return str(self.query) + ";" + str(self.engines)

View file

@ -67,8 +67,9 @@ def merge_two_infoboxes(infobox1, infobox2):
for url2 in infobox2.get('urls', []):
unique_url = True
for url1 in infobox1.get('urls', []):
if compare_urls(urlparse(url1.get('url', '')), urlparse(url2.get('url', ''))):
parsed_url2 = urlparse(url2.get('url', ''))
for url1 in urls1:
if compare_urls(urlparse(url1.get('url', '')), parsed_url2):
unique_url = False
break
if unique_url:
@ -188,8 +189,9 @@ class ResultContainer(object):
add_infobox = True
infobox_id = infobox.get('id', None)
if infobox_id is not None:
parsed_url_infobox_id = urlparse(infobox_id)
for existingIndex in self.infoboxes:
if compare_urls(urlparse(existingIndex.get('id', '')), urlparse(infobox_id)):
if compare_urls(urlparse(existingIndex.get('id', '')), parsed_url_infobox_id):
merge_two_infoboxes(existingIndex, infobox)
add_infobox = False
@ -197,6 +199,13 @@ class ResultContainer(object):
self.infoboxes.append(infobox)
def _merge_result(self, result, position):
if 'url' in result:
self.__merge_url_result(result, position)
return
self.__merge_result_no_url(result, position)
def __merge_url_result(self, result, position):
result['parsed_url'] = urlparse(result['url'])
# if the result has no scheme, use http as default
@ -210,51 +219,60 @@ class ResultContainer(object):
if result.get('content'):
result['content'] = WHITESPACE_REGEX.sub(' ', result['content'])
# check for duplicates
duplicated = False
duplicated = self.__find_duplicated_http_result(result)
if duplicated:
self.__merge_duplicated_http_result(duplicated, result, position)
return
# if there is no duplicate found, append result
result['positions'] = [position]
with RLock():
self._merged_results.append(result)
def __find_duplicated_http_result(self, result):
result_template = result.get('template')
for merged_result in self._merged_results:
if 'parsed_url' not in merged_result:
continue
if compare_urls(result['parsed_url'], merged_result['parsed_url'])\
and result_template == merged_result.get('template'):
if result_template != 'images.html':
# not an image, same template, same url : it's a duplicate
duplicated = merged_result
break
return merged_result
else:
# it's an image
# it's a duplicate if the parsed_url, template and img_src are differents
if result.get('img_src', '') == merged_result.get('img_src', ''):
duplicated = merged_result
break
return merged_result
return None
# merge duplicates together
if duplicated:
# using content with more text
if result_content_len(result.get('content', '')) >\
result_content_len(duplicated.get('content', '')):
duplicated['content'] = result['content']
def __merge_duplicated_http_result(self, duplicated, result, position):
# using content with more text
if result_content_len(result.get('content', '')) >\
result_content_len(duplicated.get('content', '')):
duplicated['content'] = result['content']
# merge all result's parameters not found in duplicate
for key in result.keys():
if not duplicated.get(key):
duplicated[key] = result.get(key)
# merge all result's parameters not found in duplicate
for key in result.keys():
if not duplicated.get(key):
duplicated[key] = result.get(key)
# add the new position
duplicated['positions'].append(position)
# add the new position
duplicated['positions'].append(position)
# add engine to list of result-engines
duplicated['engines'].add(result['engine'])
# add engine to list of result-engines
duplicated['engines'].add(result['engine'])
# using https if possible
if duplicated['parsed_url'].scheme != 'https' and result['parsed_url'].scheme == 'https':
duplicated['url'] = result['parsed_url'].geturl()
duplicated['parsed_url'] = result['parsed_url']
# using https if possible
if duplicated['parsed_url'].scheme != 'https' and result['parsed_url'].scheme == 'https':
duplicated['url'] = result['parsed_url'].geturl()
duplicated['parsed_url'] = result['parsed_url']
# if there is no duplicate found, append result
else:
result['positions'] = [position]
with RLock():
self._merged_results.append(result)
def __merge_result_no_url(self, result, position):
result['engines'] = set([result['engine']])
result['positions'] = [position]
with RLock():
self._merged_results.append(result)
def order_results(self):
for result in self._merged_results:

View file

@ -45,6 +45,16 @@ if sys.version_info[0] == 3:
logger = logger.getChild('search')
number_of_searches = 0
max_request_timeout = settings.get('outgoing', {}).get('max_request_timeout' or None)
if max_request_timeout is None:
logger.info('max_request_timeout={0}'.format(max_request_timeout))
else:
if isinstance(max_request_timeout, float):
logger.info('max_request_timeout={0} second(s)'.format(max_request_timeout))
else:
logger.critical('outgoing.max_request_timeout if defined has to be float')
from sys import exit
exit(1)
def send_http_request(engine, request_params):
@ -67,7 +77,7 @@ def send_http_request(engine, request_params):
return req(request_params['url'], **request_args)
def search_one_request(engine, query, request_params):
def search_one_http_request(engine, query, request_params):
# update request parameters dependent on
# search-engine (contained in engines folder)
engine.request(query, request_params)
@ -87,7 +97,53 @@ def search_one_request(engine, query, request_params):
return engine.response(response)
def search_one_offline_request(engine, query, request_params):
return engine.search(query, request_params)
def search_one_request_safe(engine_name, query, request_params, result_container, start_time, timeout_limit):
if engines[engine_name].offline:
return search_one_offline_request_safe(engine_name, query, request_params, result_container, start_time, timeout_limit) # noqa
return search_one_http_request_safe(engine_name, query, request_params, result_container, start_time, timeout_limit)
def search_one_offline_request_safe(engine_name, query, request_params, result_container, start_time, timeout_limit):
engine = engines[engine_name]
try:
search_results = search_one_offline_request(engine, query, request_params)
if search_results:
result_container.extend(engine_name, search_results)
engine_time = time() - start_time
result_container.add_timing(engine_name, engine_time, engine_time)
with threading.RLock():
engine.stats['engine_time'] += engine_time
engine.stats['engine_time_count'] += 1
except ValueError as e:
record_offline_engine_stats_on_error(engine, result_container, start_time)
logger.exception('engine {0} : invalid input : {1}'.format(engine_name, e))
except Exception as e:
record_offline_engine_stats_on_error(engine, result_container, start_time)
result_container.add_unresponsive_engine((
engine_name,
u'{0}: {1}'.format(gettext('unexpected crash'), e),
))
logger.exception('engine {0} : exception : {1}'.format(engine_name, e))
def record_offline_engine_stats_on_error(engine, result_container, start_time):
engine_time = time() - start_time
result_container.add_timing(engine.name, engine_time, engine_time)
with threading.RLock():
engine.stats['errors'] += 1
def search_one_http_request_safe(engine_name, query, request_params, result_container, start_time, timeout_limit):
# set timeout for all HTTP requests
requests_lib.set_timeout_for_thread(timeout_limit, start_time=start_time)
# reset the HTTP total time
@ -101,7 +157,7 @@ def search_one_request_safe(engine_name, query, request_params, result_container
try:
# send requests and parse the results
search_results = search_one_request(engine, query, request_params)
search_results = search_one_http_request(engine, query, request_params)
# check if the engine accepted the request
if search_results is not None:
@ -265,6 +321,18 @@ def get_search_query_from_webapp(preferences, form):
# query_engines
query_engines = raw_text_query.engines
# timeout_limit
query_timeout = raw_text_query.timeout_limit
if query_timeout is None and 'timeout_limit' in form:
raw_time_limit = form.get('timeout_limit')
if raw_time_limit in ['None', '']:
raw_time_limit = None
else:
try:
query_timeout = float(raw_time_limit)
except ValueError:
raise SearxParameterException('timeout_limit', raw_time_limit)
# query_categories
query_categories = []
@ -338,7 +406,8 @@ def get_search_query_from_webapp(preferences, form):
query_engines = deduplicate_query_engines(query_engines)
return (SearchQuery(query, query_engines, query_categories,
query_lang, query_safesearch, query_pageno, query_time_range),
query_lang, query_safesearch, query_pageno,
query_time_range, query_timeout),
raw_text_query)
@ -351,6 +420,7 @@ class Search(object):
super(Search, self).__init__()
self.search_query = search_query
self.result_container = ResultContainer()
self.actual_timeout = None
# do search-request
def search(self):
@ -380,7 +450,7 @@ class Search(object):
search_query = self.search_query
# max of all selected engine timeout
timeout_limit = 0
default_timeout = 0
# start search-reqest for all selected engines
for selected_engine in search_query.engines:
@ -403,29 +473,51 @@ class Search(object):
continue
# set default request parameters
request_params = default_request_params()
request_params['headers']['User-Agent'] = user_agent
request_params = {}
if not engine.offline:
request_params = default_request_params()
request_params['headers']['User-Agent'] = user_agent
if hasattr(engine, 'language') and engine.language:
request_params['language'] = engine.language
else:
request_params['language'] = search_query.lang
request_params['safesearch'] = search_query.safesearch
request_params['time_range'] = search_query.time_range
request_params['category'] = selected_engine['category']
request_params['pageno'] = search_query.pageno
if hasattr(engine, 'language') and engine.language:
request_params['language'] = engine.language
else:
request_params['language'] = search_query.lang
# 0 = None, 1 = Moderate, 2 = Strict
request_params['safesearch'] = search_query.safesearch
request_params['time_range'] = search_query.time_range
# append request to list
requests.append((selected_engine['name'], search_query.query, request_params))
# update timeout_limit
timeout_limit = max(timeout_limit, engine.timeout)
# update default_timeout
default_timeout = max(default_timeout, engine.timeout)
# adjust timeout
self.actual_timeout = default_timeout
query_timeout = self.search_query.timeout_limit
if max_request_timeout is None and query_timeout is None:
# No max, no user query: default_timeout
pass
elif max_request_timeout is None and query_timeout is not None:
# No max, but user query: From user query except if above default
self.actual_timeout = min(default_timeout, query_timeout)
elif max_request_timeout is not None and query_timeout is None:
# Max, no user query: Default except if above max
self.actual_timeout = min(default_timeout, max_request_timeout)
elif max_request_timeout is not None and query_timeout is not None:
# Max & user query: From user query except if above max
self.actual_timeout = min(query_timeout, max_request_timeout)
logger.debug("actual_timeout={0} (default_timeout={1}, ?timeout_limit={2}, max_request_timeout={3})"
.format(self.actual_timeout, default_timeout, query_timeout, max_request_timeout))
# send all search-request
if requests:
# send all search-request
search_multiple_requests(requests, self.result_container, start_time, timeout_limit)
search_multiple_requests(requests, self.result_container, start_time, self.actual_timeout)
start_new_thread(gc.collect, tuple())
# return results, suggestions, answers and infoboxes

View file

@ -34,7 +34,8 @@ ui:
# key : !!binary "your_morty_proxy_key"
outgoing: # communication with search engines
request_timeout : 2.0 # seconds
request_timeout : 2.0 # default timeout in seconds, can be override by engine
# max_request_timeout: 10.0 # the maximum timeout in seconds
useragent_suffix : "" # suffix of searx_useragent, could contain informations like an email address to the administrator
pool_connections : 100 # Number of different hosts
pool_maxsize : 10 # Number of simultaneous requests by host
@ -160,11 +161,12 @@ engines:
weight : 2
disabled : True
- name : digbt
engine : digbt
shortcut : dbt
timeout : 6.0
disabled : True
# cloudflare protected
# - name : digbt
# engine : digbt
# shortcut : dbt
# timeout : 6.0
# disabled : True
- name : digg
engine : digg
@ -203,11 +205,11 @@ engines:
- name : etymonline
engine : xpath
paging : True
search_url : http://etymonline.com/?search={query}&p={pageno}
url_xpath : //a[contains(@class, "word--")]/@href
title_xpath : //p[contains(@class, "word__name--")]/text()
content_xpath : //section[contains(@class, "word__defination")]/object
first_page_num : 0
search_url : https://etymonline.com/search?page={pageno}&q={query}
url_xpath : //a[contains(@class, "word__name--")]/@href
title_xpath : //a[contains(@class, "word__name--")]
content_xpath : //section[contains(@class, "word__defination")]
first_page_num : 1
shortcut : et
disabled : True
@ -392,6 +394,12 @@ engines:
timeout : 6.0
disabled : True
- name : invidious
engine : invidious
base_url : 'https://invidio.us/'
shortcut: iv
timeout : 5.0
- name: kickass
engine : kickass
shortcut : kc
@ -400,7 +408,7 @@ engines:
- name : library genesis
engine : xpath
search_url : http://libgen.io/search.php?req={query}
search_url : https://libgen.is/search.php?req={query}
url_xpath : //a[contains(@href,"bookfi.net")]/@href
title_xpath : //a[contains(@href,"book/")]/text()[1]
content_xpath : //td/a[1][contains(@href,"=author")]/text()
@ -456,7 +464,7 @@ engines:
- name : openairedatasets
engine : json_engine
paging : True
search_url : http://api.openaire.eu/search/datasets?format=json&page={pageno}&size=10&title={query}
search_url : https://api.openaire.eu/search/datasets?format=json&page={pageno}&size=10&title={query}
results_query : response/results/result
url_query : metadata/oaf:entity/oaf:result/children/instance/webresource/url/$
title_query : metadata/oaf:entity/oaf:result/title/$
@ -468,7 +476,7 @@ engines:
- name : openairepublications
engine : json_engine
paging : True
search_url : http://api.openaire.eu/search/publications?format=json&page={pageno}&size=10&title={query}
search_url : https://api.openaire.eu/search/publications?format=json&page={pageno}&size=10&title={query}
results_query : response/results/result
url_query : metadata/oaf:entity/oaf:result/children/instance/webresource/url/$
title_query : metadata/oaf:entity/oaf:result/title/$
@ -699,9 +707,9 @@ engines:
shortcut: vo
categories: social media
search_url : https://searchvoat.co/?t={query}
url_xpath : //div[@class="entry"]/p/a[@class="title"]/@href
title_xpath : //div[@class="entry"]/p/a[@class="title"]
content_xpath : //div[@class="entry"]/p/span[@class="domain"]
url_xpath : //div[@class="entry"]//p[@class="title"]/a/@href
title_xpath : //div[@class="entry"]//p[@class="title"]/a/text()
content_xpath : //div[@class="entry"]//span[@class="domain"]/a/text()
timeout : 10.0
disabled : True
@ -739,10 +747,15 @@ engines:
title_xpath : ./h2
content_xpath : ./p[@class="s"]
suggestion_xpath : /html/body//div[@class="top-info"]/p[@class="top-info spell"]/a
first_page_num : 1
first_page_num : 0
page_size : 10
disabled : True
- name : seedpeer
shortcut : speu
engine : seedpeer
categories: files, music, videos
# - name : yacy
# engine : yacy
# shortcut : ya
@ -802,7 +815,7 @@ locales:
doi_resolvers :
oadoi.org : 'https://oadoi.org/'
doi.org : 'https://doi.org/'
doai.io : 'http://doai.io/'
sci-hub.tw : 'http://sci-hub.tw/'
doai.io : 'https://doai.io/'
sci-hub.tw : 'https://sci-hub.tw/'
default_doi_resolver : 'oadoi.org'

View file

@ -43,7 +43,7 @@ locales:
doi_resolvers :
oadoi.org : 'https://oadoi.org/'
doi.org : 'https://doi.org/'
doai.io : 'http://doai.io/'
sci-hub.tw : 'http://sci-hub.tw/'
doai.io : 'https://doai.io/'
sci-hub.tw : 'https://sci-hub.tw/'
default_doi_resolver : 'oadoi.org'

File diff suppressed because one or more lines are too long

View file

@ -125,6 +125,14 @@ $(document).ready(function() {
}
});
function nextResult(current, direction) {
var next = current[direction]();
while (!next.is('.result') && next.length !== 0) {
next = next[direction]();
}
return next
}
function highlightResult(which) {
return function() {
var current = $('.result[data-vim-selected]');
@ -157,13 +165,13 @@ $(document).ready(function() {
}
break;
case 'down':
next = current.next('.result');
next = nextResult(current, 'next');
if (next.length === 0) {
next = $('.result:first');
}
break;
case 'up':
next = current.prev('.result');
next = nextResult(current, 'prev');
if (next.length === 0) {
next = $('.result:last');
}

View file

@ -1 +1 @@
.q{padding:.5em 1em .5em 3em}#search_submit{left:0;right:auto}.result .favicon{float:right;margin-left:.5em;margin-right:0}#sidebar{right:auto;left:0}#results{padding:0 32px 0 272px}.search.center{padding-right:0;padding-left:17em}.right{right:auto;left:0}#pagination form+form{float:left;margin-top:-2em}.engine-table{text-align:right}
#search_submit,#sidebar,.right{right:auto;left:0}.q{padding:.5em 1em .5em 3em}.result .favicon{float:right;margin-left:.5em;margin-right:0}#results{padding:0 32px 0 272px}.search.center{padding-right:0;padding-left:17em}#pagination form+form{float:left;margin-top:-2em}.engine-table{text-align:right}

File diff suppressed because one or more lines are too long

View file

@ -325,6 +325,10 @@ a {
font-size: 0.9em;
}
.result .engines {
text-align: right;
}
.result .content {
margin: 0;
color: #666;

File diff suppressed because one or more lines are too long

View file

@ -1,61 +1,61 @@
/*
* searx, A privacy-respecting, hackable metasearch engine
*/
ul {
&.autocompleter-choices {
position: absolute;
margin: 0;
padding: 0;
list-style: none;
border: 1px solid @color-autocompleter-choices-border;
border-left-color: @color-autocompleter-choices-border-left-right;
border-right-color: @color-autocompleter-choices-border-left-right;
border-bottom-color: @color-autocompleter-choices-border-bottom;
text-align: left;
font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
z-index: 50;
background-color: @color-autocompleter-choices-background;
color: @color-autocompleter-choices-font;
li {
position: relative;
margin: -2px 0 0 0;
padding: 0.2em 1.5em 0.2em 1em;
display: block;
float: none !important;
cursor: pointer;
font-weight: normal;
white-space: nowrap;
font-size: 1em;
line-height: 1.5em;
&.autocompleter-selected {
background-color: @color-autocompleter-selected-background;
color: @color-autocompleter-selected-font;
span.autocompleter-queried {
color: @color-autocompleter-selected-queried-font;
}
}
}
span.autocompleter-queried {
display: inline;
float: none;
font-weight: bold;
margin: 0;
padding: 0;
}
}
}
/*.autocompleter-loading {
//background-image: url(images/spinner.gif);
background-repeat: no-repeat;
background-position: right 50%;
}*/
/*textarea.autocompleter-loading {
background-position: right bottom;
}*/
/*
* searx, A privacy-respecting, hackable metasearch engine
*/
ul {
&.autocompleter-choices {
position: absolute;
margin: 0;
padding: 0;
list-style: none;
border: 1px solid @color-autocompleter-choices-border;
border-left-color: @color-autocompleter-choices-border-left-right;
border-right-color: @color-autocompleter-choices-border-left-right;
border-bottom-color: @color-autocompleter-choices-border-bottom;
text-align: left;
font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
z-index: 50;
background-color: @color-autocompleter-choices-background;
color: @color-autocompleter-choices-font;
li {
position: relative;
margin: -2px 0 0 0;
padding: 0.2em 1.5em 0.2em 1em;
display: block;
float: none !important;
cursor: pointer;
font-weight: normal;
white-space: nowrap;
font-size: 1em;
line-height: 1.5em;
&.autocompleter-selected {
background-color: @color-autocompleter-selected-background;
color: @color-autocompleter-selected-font;
span.autocompleter-queried {
color: @color-autocompleter-selected-queried-font;
}
}
}
span.autocompleter-queried {
display: inline;
float: none;
font-weight: bold;
margin: 0;
padding: 0;
}
}
}
/*.autocompleter-loading {
//background-image: url(images/spinner.gif);
background-repeat: no-repeat;
background-position: right 50%;
}*/
/*textarea.autocompleter-loading {
background-position: right bottom;
}*/

View file

@ -376,6 +376,10 @@ table {
width: 100%;
}
.result-table {
margin-bottom: 10px;
}
td {
padding: 0 4px;
}

View file

@ -0,0 +1,732 @@
.searx-navbar {
background: #29314d;
height: 2.3rem;
font-size: 1.3rem;
line-height: 1.3rem;
padding: 0.5rem;
font-weight: bold;
margin-bottom: 0.8rem;
}
.searx-navbar a,
.searx-navbar a:hover {
margin-right: 2.0rem;
color: white;
text-decoration: none;
}
.searx-navbar .instance a {
color: #01d7d4;
margin-left: 2.0rem;
}
#main-logo {
margin-top: 20vh;
margin-bottom: 25px;
}
#main-logo > img {
max-width: 350px;
width: 80%;
}
* {
border-radius: 0 !important;
}
html {
position: relative;
min-height: 100%;
color: #29314d;
}
body {
/* Margin bottom by footer height */
font-family: 'Roboto', Helvetica, Arial, sans-serif;
margin-bottom: 80px;
background-color: white;
}
body a {
color: #0088cc;
}
.footer {
position: absolute;
bottom: 0;
width: 100%;
/* Set the fixed height of the footer here */
height: 60px;
text-align: center;
color: #999;
}
input[type=checkbox]:checked + .label_hide_if_checked,
input[type=checkbox]:checked + .label_hide_if_not_checked + .label_hide_if_checked {
display: none;
}
input[type=checkbox]:not(:checked) + .label_hide_if_not_checked,
input[type=checkbox]:not(:checked) + .label_hide_if_checked + .label_hide_if_not_checked {
display: none;
}
.onoff-checkbox {
width: 15%;
}
.onoffswitch {
position: relative;
width: 110px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
}
.onoffswitch-checkbox {
display: none;
}
.onoffswitch-label {
display: block;
overflow: hidden;
cursor: pointer;
border: 2px solid #FFFFFF !important;
border-radius: 50px !important;
}
.onoffswitch-inner {
display: block;
transition: margin 0.3s ease-in 0s;
}
.onoffswitch-inner:before,
.onoffswitch-inner:after {
display: block;
float: left;
width: 50%;
height: 30px;
padding: 0;
line-height: 40px;
font-size: 20px;
box-sizing: border-box;
content: "";
background-color: #EEEEEE;
}
.onoffswitch-switch {
display: block;
width: 37px;
background-color: #01d7d4;
position: absolute;
top: 0;
bottom: 0;
right: 0px;
border: 2px solid #FFFFFF !important;
border-radius: 50px !important;
transition: all 0.3s ease-in 0s;
}
.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-inner {
margin-right: 0;
}
.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-switch {
right: 71px;
background-color: #A1A1A1;
}
.result_header {
margin-top: 0px;
margin-bottom: 2px;
font-size: 16px;
}
.result_header .favicon {
margin-bottom: -3px;
}
.result_header a {
color: #29314d;
text-decoration: none;
}
.result_header a:hover {
color: #0088cc;
}
.result_header a:visited {
color: #684898;
}
.result_header a .highlight {
background-color: #f6f9fa;
}
.result-content,
.result-format,
.result-source {
margin-top: 2px;
margin-bottom: 0;
word-wrap: break-word;
color: #666666;
font-size: 13px;
}
.result-content .highlight,
.result-format .highlight,
.result-source .highlight {
font-weight: bold;
}
.result-source {
font-size: 10px;
float: left;
}
.result-format {
font-size: 10px;
float: right;
}
.external-link {
color: #069025;
font-size: 12px;
margin-bottom: 15px;
}
.external-link a {
margin-right: 3px;
}
.result-default,
.result-code,
.result-torrent,
.result-videos,
.result-map {
clear: both;
padding: 2px 4px;
}
.result-default:hover,
.result-code:hover,
.result-torrent:hover,
.result-videos:hover,
.result-map:hover {
background-color: #f6f9fa;
}
.result-images {
float: left !important;
width: 24%;
margin: .5%;
}
.result-images a {
display: block;
width: 100%;
background-size: cover;
}
.img-thumbnail {
margin: 5px;
max-height: 128px;
min-height: 128px;
}
.result-videos {
clear: both;
}
.result-videos hr {
margin: 5px 0 15px 0;
}
.result-videos .collapse {
width: 100%;
}
.result-videos .in {
margin-bottom: 8px;
}
.result-torrent {
clear: both;
}
.result-torrent b {
margin-right: 5px;
margin-left: 5px;
}
.result-torrent .seeders {
color: #2ecc71;
}
.result-torrent .leechers {
color: #f35e77;
}
.result-map {
clear: both;
}
.result-code {
clear: both;
}
.result-code .code-fork,
.result-code .code-fork a {
color: #666666;
}
.suggestion_item {
margin: 2px 5px;
max-width: 100%;
}
.suggestion_item .btn {
max-width: 100%;
white-space: normal;
word-wrap: break-word;
text-align: left;
}
.result_download {
margin-right: 5px;
}
#pagination {
margin-top: 30px;
padding-bottom: 60px;
}
.label-default {
color: #a4a4a4;
background: transparent;
}
.result .text-muted small {
word-wrap: break-word;
}
.modal-wrapper {
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
}
.modal-wrapper {
background-clip: padding-box;
background-color: #fff;
border: 1px solid rgba(0, 0, 0, 0.2);
border-radius: 6px;
box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);
outline: 0 none;
position: relative;
}
.infobox .panel-heading {
background-color: #f6f9fa;
}
.infobox .panel-heading .panel-title {
font-weight: 700;
}
.infobox p {
font-family: "DejaVu Serif", Georgia, Cambria, "Times New Roman", Times, serif !important;
font-style: italic;
}
.infobox .btn {
background-color: #2ecc71;
border: none;
}
.infobox .btn a {
color: white;
margin: 5px;
}
.infobox .infobox_part {
margin-bottom: 20px;
word-wrap: break-word;
table-layout: fixed;
}
.infobox .infobox_part:last-child {
margin-bottom: 0;
}
.search_categories,
#categories {
text-transform: capitalize;
margin-bottom: 0.5rem;
display: flex;
flex-wrap: wrap;
flex-flow: row wrap;
align-content: stretch;
}
.search_categories label,
#categories label,
.search_categories .input-group-addon,
#categories .input-group-addon {
flex-grow: 1;
flex-basis: auto;
font-size: 1.2rem;
font-weight: normal;
background-color: white;
border: #dddddd 1px solid;
border-right: none;
color: #666666;
padding-bottom: 0.4rem;
padding-top: 0.4rem;
text-align: center;
min-width: 50px;
}
.search_categories label:last-child,
#categories label:last-child,
.search_categories .input-group-addon:last-child,
#categories .input-group-addon:last-child {
border-right: #dddddd 1px solid;
}
.search_categories input[type="checkbox"]:checked + label,
#categories input[type="checkbox"]:checked + label {
color: #29314d;
font-weight: bold;
border-bottom: #01d7d4 5px solid;
}
#main-logo {
margin-top: 10vh;
margin-bottom: 25px;
}
#main-logo > img {
max-width: 350px;
width: 80%;
}
#q {
box-shadow: none;
border-right: none;
border-color: #a4a4a4;
}
#search_form .input-group-btn .btn {
border-color: #a4a4a4;
}
#search_form .input-group-btn .btn:hover {
background-color: #2ecc71;
color: white;
}
.custom-select {
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
font-size: 1.2rem;
font-weight: normal;
background-color: white;
border: #dddddd 1px solid;
color: #666666;
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAQAAACR313BAAAABGdBTUEAALGPC/xhBQAAACBjSFJN
AAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAAJcEhZ
cwAABFkAAARZAVnbJUkAAAAHdElNRQfgBxgLDwB20OFsAAAAbElEQVQY073OsQ3CMAAEwJMYwJGn
sAehpoXJItltBkmcdZBYgIIiQoLglnz3ui+eP+bk5uneteTMZJa6OJuIqvYzSJoqwqBq8gdmTTW8
6/dghxAUq4xsVYT9laBYXCw93Aajh7GPEF23t4fkBYevGFTANkPRAAAAJXRFWHRkYXRlOmNyZWF0
ZQAyMDE2LTA3LTI0VDExOjU1OjU4KzAyOjAwRFqFOQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNi0w
Ny0yNFQxMToxNTowMCswMjowMP7RDgQAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb
7jwaAAAAAElFTkSuQmCC) 96% no-repeat;
}
.search-margin {
margin-bottom: 0.6em;
}
#advanced-search-container {
display: none;
text-align: left;
margin-bottom: 1rem;
clear: both;
}
#advanced-search-container label,
#advanced-search-container .input-group-addon {
font-size: 1.2rem;
font-weight: normal;
background-color: white;
border: #dddddd 1px solid;
border-right: none;
color: #666666;
padding-bottom: 0.4rem;
padding-right: 0.7rem;
padding-left: 0.7rem;
}
#advanced-search-container label:last-child,
#advanced-search-container .input-group-addon:last-child {
border-right: #dddddd 1px solid;
}
#advanced-search-container input[type="radio"] {
display: none;
}
#advanced-search-container input[type="radio"]:checked + label {
color: #29314d;
font-weight: bold;
border-bottom: #01d7d4 5px solid;
}
#check-advanced {
display: none;
}
#check-advanced:checked ~ #advanced-search-container {
display: block;
}
.advanced {
padding: 0;
margin-top: 0.3rem;
text-align: right;
}
.advanced label,
.advanced select {
cursor: pointer;
}
.cursor-text {
cursor: text !important;
}
.cursor-pointer {
cursor: pointer !important;
}
pre,
code {
font-family: 'Ubuntu Mono', 'Courier New', 'Lucida Console', monospace !important;
}
.lineno {
margin-right: 5px;
}
.highlight .hll {
background-color: #ffffcc;
}
.highlight {
background: #f8f8f8;
}
.highlight .c {
color: #556366;
font-style: italic;
}
/* Comment */
.highlight .err {
border: 1px solid #ffa92f;
}
/* Error */
.highlight .k {
color: #BE74D5;
font-weight: bold;
}
/* Keyword */
.highlight .o {
color: #d19a66;
}
/* Operator */
.highlight .cm {
color: #556366;
font-style: italic;
}
/* Comment.Multiline */
.highlight .cp {
color: #bc7a00;
}
/* Comment.Preproc */
.highlight .c1 {
color: #556366;
font-style: italic;
}
/* Comment.Single */
.highlight .cs {
color: #556366;
font-style: italic;
}
/* Comment.Special */
.highlight .gd {
color: #a00000;
}
/* Generic.Deleted */
.highlight .ge {
font-style: italic;
}
/* Generic.Emph */
.highlight .gr {
color: #ff0000;
}
/* Generic.Error */
.highlight .gh {
color: #000080;
font-weight: bold;
}
/* Generic.Heading */
.highlight .gi {
color: #00a000;
}
/* Generic.Inserted */
.highlight .go {
color: #888888;
}
/* Generic.Output */
.highlight .gp {
color: #000080;
font-weight: bold;
}
/* Generic.Prompt */
.highlight .gs {
font-weight: bold;
}
/* Generic.Strong */
.highlight .gu {
color: #800080;
font-weight: bold;
}
/* Generic.Subheading */
.highlight .gt {
color: #0044dd;
}
/* Generic.Traceback */
.highlight .kc {
color: #BE74D5;
font-weight: bold;
}
/* Keyword.Constant */
.highlight .kd {
color: #BE74D5;
font-weight: bold;
}
/* Keyword.Declaration */
.highlight .kn {
color: #BE74D5;
font-weight: bold;
}
/* Keyword.Namespace */
.highlight .kp {
color: #be74d5;
}
/* Keyword.Pseudo */
.highlight .kr {
color: #BE74D5;
font-weight: bold;
}
/* Keyword.Reserved */
.highlight .kt {
color: #d46c72;
}
/* Keyword.Type */
.highlight .m {
color: #d19a66;
}
/* Literal.Number */
.highlight .s {
color: #86c372;
}
/* Literal.String */
.highlight .na {
color: #7d9029;
}
/* Name.Attribute */
.highlight .nb {
color: #be74d5;
}
/* Name.Builtin */
.highlight .nc {
color: #61AFEF;
font-weight: bold;
}
/* Name.Class */
.highlight .no {
color: #d19a66;
}
/* Name.Constant */
.highlight .nd {
color: #aa22ff;
}
/* Name.Decorator */
.highlight .ni {
color: #999999;
font-weight: bold;
}
/* Name.Entity */
.highlight .ne {
color: #D2413A;
font-weight: bold;
}
/* Name.Exception */
.highlight .nf {
color: #61afef;
}
/* Name.Function */
.highlight .nl {
color: #a0a000;
}
/* Name.Label */
.highlight .nn {
color: #61AFEF;
font-weight: bold;
}
/* Name.Namespace */
.highlight .nt {
color: #BE74D5;
font-weight: bold;
}
/* Name.Tag */
.highlight .nv {
color: #dfc06f;
}
/* Name.Variable */
.highlight .ow {
color: #AA22FF;
font-weight: bold;
}
/* Operator.Word */
.highlight .w {
color: #d7dae0;
}
/* Text.Whitespace */
.highlight .mf {
color: #d19a66;
}
/* Literal.Number.Float */
.highlight .mh {
color: #d19a66;
}
/* Literal.Number.Hex */
.highlight .mi {
color: #d19a66;
}
/* Literal.Number.Integer */
.highlight .mo {
color: #d19a66;
}
/* Literal.Number.Oct */
.highlight .sb {
color: #86c372;
}
/* Literal.String.Backtick */
.highlight .sc {
color: #86c372;
}
/* Literal.String.Char */
.highlight .sd {
color: #86C372;
font-style: italic;
}
/* Literal.String.Doc */
.highlight .s2 {
color: #86c372;
}
/* Literal.String.Double */
.highlight .se {
color: #BB6622;
font-weight: bold;
}
/* Literal.String.Escape */
.highlight .sh {
color: #86c372;
}
/* Literal.String.Heredoc */
.highlight .si {
color: #BB6688;
font-weight: bold;
}
/* Literal.String.Interpol */
.highlight .sx {
color: #be74d5;
}
/* Literal.String.Other */
.highlight .sr {
color: #bb6688;
}
/* Literal.String.Regex */
.highlight .s1 {
color: #86c372;
}
/* Literal.String.Single */
.highlight .ss {
color: #dfc06f;
}
/* Literal.String.Symbol */
.highlight .bp {
color: #be74d5;
}
/* Name.Builtin.Pseudo */
.highlight .vc {
color: #dfc06f;
}
/* Name.Variable.Class */
.highlight .vg {
color: #dfc06f;
}
/* Name.Variable.Global */
.highlight .vi {
color: #dfc06f;
}
/* Name.Variable.Instance */
.highlight .il {
color: #d19a66;
}
/* Literal.Number.Integer.Long */
.highlight .lineno {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
cursor: default;
color: #556366;
}
.highlight .lineno::selection {
background: transparent;
/* WebKit/Blink Browsers */
}
.highlight .lineno::-moz-selection {
background: transparent;
/* Gecko Browsers */
}
.highlight pre {
background-color: #282C34;
color: #D7DAE0;
border: none;
margin-bottom: 25px;
font-size: 15px;
padding: 20px 10px;
}
.highlight {
font-weight: 700;
}
.table > tbody > tr > td,
.table > tbody > tr > th {
vertical-align: middle !important;
}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,931 @@
* {
border-radius: 0 !important;
}
html {
position: relative;
min-height: 100%;
color: #29314d;
}
body {
/* Margin bottom by footer height */
font-family: 'Roboto', Helvetica, Arial, sans-serif;
margin-bottom: 80px;
background-color: white;
}
body a {
color: #0088cc;
}
.footer {
position: absolute;
bottom: 0;
width: 100%;
/* Set the fixed height of the footer here */
height: 60px;
text-align: center;
color: #999;
}
input[type=checkbox]:checked + .label_hide_if_checked,
input[type=checkbox]:checked + .label_hide_if_not_checked + .label_hide_if_checked {
display: none;
}
input[type=checkbox]:not(:checked) + .label_hide_if_not_checked,
input[type=checkbox]:not(:checked) + .label_hide_if_checked + .label_hide_if_not_checked {
display: none;
}
.onoff-checkbox {
width: 15%;
}
.onoffswitch {
position: relative;
width: 110px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
}
.onoffswitch-checkbox {
display: none;
}
.onoffswitch-label {
display: block;
overflow: hidden;
cursor: pointer;
border: 2px solid #FFFFFF !important;
border-radius: 50px !important;
}
.onoffswitch-inner {
display: block;
transition: margin 0.3s ease-in 0s;
}
.onoffswitch-inner:before,
.onoffswitch-inner:after {
display: block;
float: left;
width: 50%;
height: 30px;
padding: 0;
line-height: 40px;
font-size: 20px;
box-sizing: border-box;
content: "";
background-color: #EEEEEE;
}
.onoffswitch-switch {
display: block;
width: 37px;
background-color: #01d7d4;
position: absolute;
top: 0;
bottom: 0;
right: 0px;
border: 2px solid #FFFFFF !important;
border-radius: 50px !important;
transition: all 0.3s ease-in 0s;
}
.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-inner {
margin-right: 0;
}
.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-switch {
right: 71px;
background-color: #A1A1A1;
}
.result_header {
margin-top: 0px;
margin-bottom: 2px;
font-size: 16px;
}
.result_header .favicon {
margin-bottom: -3px;
}
.result_header a {
color: #29314d;
text-decoration: none;
}
.result_header a:hover {
color: #0088cc;
}
.result_header a:visited {
color: #684898;
}
.result_header a .highlight {
background-color: #f6f9fa;
}
.result-content,
.result-format,
.result-source {
margin-top: 2px;
margin-bottom: 0;
word-wrap: break-word;
color: #666666;
font-size: 13px;
}
.result-content .highlight,
.result-format .highlight,
.result-source .highlight {
font-weight: bold;
}
.result-source {
font-size: 10px;
float: left;
}
.result-format {
font-size: 10px;
float: right;
}
.external-link {
color: #069025;
font-size: 12px;
margin-bottom: 15px;
}
.external-link a {
margin-right: 3px;
}
.result-default,
.result-code,
.result-torrent,
.result-videos,
.result-map {
clear: both;
padding: 2px 4px;
}
.result-default:hover,
.result-code:hover,
.result-torrent:hover,
.result-videos:hover,
.result-map:hover {
background-color: #f6f9fa;
}
.result-images {
float: left !important;
width: 24%;
margin: .5%;
}
.result-images a {
display: block;
width: 100%;
background-size: cover;
}
.img-thumbnail {
margin: 5px;
max-height: 128px;
min-height: 128px;
}
.result-videos {
clear: both;
}
.result-videos hr {
margin: 5px 0 15px 0;
}
.result-videos .collapse {
width: 100%;
}
.result-videos .in {
margin-bottom: 8px;
}
.result-torrent {
clear: both;
}
.result-torrent b {
margin-right: 5px;
margin-left: 5px;
}
.result-torrent .seeders {
color: #2ecc71;
}
.result-torrent .leechers {
color: #f35e77;
}
.result-map {
clear: both;
}
.result-code {
clear: both;
}
.result-code .code-fork,
.result-code .code-fork a {
color: #666666;
}
.suggestion_item {
margin: 2px 5px;
max-width: 100%;
}
.suggestion_item .btn {
max-width: 100%;
white-space: normal;
word-wrap: break-word;
text-align: left;
}
.result_download {
margin-right: 5px;
}
#pagination {
margin-top: 30px;
padding-bottom: 60px;
}
.label-default {
color: #a4a4a4;
background: transparent;
}
.result .text-muted small {
word-wrap: break-word;
}
.modal-wrapper {
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
}
.modal-wrapper {
background-clip: padding-box;
background-color: #fff;
border: 1px solid rgba(0, 0, 0, 0.2);
border-radius: 6px;
box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);
outline: 0 none;
position: relative;
}
.infobox .panel-heading {
background-color: #f6f9fa;
}
.infobox .panel-heading .panel-title {
font-weight: 700;
}
.infobox p {
font-family: "DejaVu Serif", Georgia, Cambria, "Times New Roman", Times, serif !important;
font-style: italic;
}
.infobox .btn {
background-color: #2ecc71;
border: none;
}
.infobox .btn a {
color: white;
margin: 5px;
}
.infobox .infobox_part {
margin-bottom: 20px;
word-wrap: break-word;
table-layout: fixed;
}
.infobox .infobox_part:last-child {
margin-bottom: 0;
}
.search_categories,
#categories {
text-transform: capitalize;
margin-bottom: 0.5rem;
display: flex;
flex-wrap: wrap;
flex-flow: row wrap;
align-content: stretch;
}
.search_categories label,
#categories label,
.search_categories .input-group-addon,
#categories .input-group-addon {
flex-grow: 1;
flex-basis: auto;
font-size: 1.2rem;
font-weight: normal;
background-color: white;
border: #dddddd 1px solid;
border-right: none;
color: #666666;
padding-bottom: 0.4rem;
padding-top: 0.4rem;
text-align: center;
min-width: 50px;
}
.search_categories label:last-child,
#categories label:last-child,
.search_categories .input-group-addon:last-child,
#categories .input-group-addon:last-child {
border-right: #dddddd 1px solid;
}
.search_categories input[type="checkbox"]:checked + label,
#categories input[type="checkbox"]:checked + label {
color: #29314d;
font-weight: bold;
border-bottom: #01d7d4 5px solid;
}
#main-logo {
margin-top: 10vh;
margin-bottom: 25px;
}
#main-logo > img {
max-width: 350px;
width: 80%;
}
#q {
box-shadow: none;
border-right: none;
border-color: #a4a4a4;
}
#search_form .input-group-btn .btn {
border-color: #a4a4a4;
}
#search_form .input-group-btn .btn:hover {
background-color: #2ecc71;
color: white;
}
.custom-select {
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
font-size: 1.2rem;
font-weight: normal;
background-color: white;
border: #dddddd 1px solid;
color: #666666;
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAQAAACR313BAAAABGdBTUEAALGPC/xhBQAAACBjSFJN
AAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAAJcEhZ
cwAABFkAAARZAVnbJUkAAAAHdElNRQfgBxgLDwB20OFsAAAAbElEQVQY073OsQ3CMAAEwJMYwJGn
sAehpoXJItltBkmcdZBYgIIiQoLglnz3ui+eP+bk5uneteTMZJa6OJuIqvYzSJoqwqBq8gdmTTW8
6/dghxAUq4xsVYT9laBYXCw93Aajh7GPEF23t4fkBYevGFTANkPRAAAAJXRFWHRkYXRlOmNyZWF0
ZQAyMDE2LTA3LTI0VDExOjU1OjU4KzAyOjAwRFqFOQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNi0w
Ny0yNFQxMToxNTowMCswMjowMP7RDgQAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb
7jwaAAAAAElFTkSuQmCC) 96% no-repeat;
}
.search-margin {
margin-bottom: 0.6em;
}
#advanced-search-container {
display: none;
text-align: left;
margin-bottom: 1rem;
clear: both;
}
#advanced-search-container label,
#advanced-search-container .input-group-addon {
font-size: 1.2rem;
font-weight: normal;
background-color: white;
border: #dddddd 1px solid;
border-right: none;
color: #666666;
padding-bottom: 0.4rem;
padding-right: 0.7rem;
padding-left: 0.7rem;
}
#advanced-search-container label:last-child,
#advanced-search-container .input-group-addon:last-child {
border-right: #dddddd 1px solid;
}
#advanced-search-container input[type="radio"] {
display: none;
}
#advanced-search-container input[type="radio"]:checked + label {
color: #29314d;
font-weight: bold;
border-bottom: #01d7d4 5px solid;
}
#check-advanced {
display: none;
}
#check-advanced:checked ~ #advanced-search-container {
display: block;
}
.advanced {
padding: 0;
margin-top: 0.3rem;
text-align: right;
}
.advanced label,
.advanced select {
cursor: pointer;
}
.cursor-text {
cursor: text !important;
}
.cursor-pointer {
cursor: pointer !important;
}
pre,
code {
font-family: 'Ubuntu Mono', 'Courier New', 'Lucida Console', monospace !important;
}
.lineno {
margin-right: 5px;
}
.highlight .hll {
background-color: #ffffcc;
}
.highlight {
background: #f8f8f8;
}
.highlight .c {
color: #556366;
font-style: italic;
}
/* Comment */
.highlight .err {
border: 1px solid #ffa92f;
}
/* Error */
.highlight .k {
color: #BE74D5;
font-weight: bold;
}
/* Keyword */
.highlight .o {
color: #d19a66;
}
/* Operator */
.highlight .cm {
color: #556366;
font-style: italic;
}
/* Comment.Multiline */
.highlight .cp {
color: #bc7a00;
}
/* Comment.Preproc */
.highlight .c1 {
color: #556366;
font-style: italic;
}
/* Comment.Single */
.highlight .cs {
color: #556366;
font-style: italic;
}
/* Comment.Special */
.highlight .gd {
color: #a00000;
}
/* Generic.Deleted */
.highlight .ge {
font-style: italic;
}
/* Generic.Emph */
.highlight .gr {
color: #ff0000;
}
/* Generic.Error */
.highlight .gh {
color: #000080;
font-weight: bold;
}
/* Generic.Heading */
.highlight .gi {
color: #00a000;
}
/* Generic.Inserted */
.highlight .go {
color: #888888;
}
/* Generic.Output */
.highlight .gp {
color: #000080;
font-weight: bold;
}
/* Generic.Prompt */
.highlight .gs {
font-weight: bold;
}
/* Generic.Strong */
.highlight .gu {
color: #800080;
font-weight: bold;
}
/* Generic.Subheading */
.highlight .gt {
color: #0044dd;
}
/* Generic.Traceback */
.highlight .kc {
color: #BE74D5;
font-weight: bold;
}
/* Keyword.Constant */
.highlight .kd {
color: #BE74D5;
font-weight: bold;
}
/* Keyword.Declaration */
.highlight .kn {
color: #BE74D5;
font-weight: bold;
}
/* Keyword.Namespace */
.highlight .kp {
color: #be74d5;
}
/* Keyword.Pseudo */
.highlight .kr {
color: #BE74D5;
font-weight: bold;
}
/* Keyword.Reserved */
.highlight .kt {
color: #d46c72;
}
/* Keyword.Type */
.highlight .m {
color: #d19a66;
}
/* Literal.Number */
.highlight .s {
color: #86c372;
}
/* Literal.String */
.highlight .na {
color: #7d9029;
}
/* Name.Attribute */
.highlight .nb {
color: #be74d5;
}
/* Name.Builtin */
.highlight .nc {
color: #61AFEF;
font-weight: bold;
}
/* Name.Class */
.highlight .no {
color: #d19a66;
}
/* Name.Constant */
.highlight .nd {
color: #aa22ff;
}
/* Name.Decorator */
.highlight .ni {
color: #999999;
font-weight: bold;
}
/* Name.Entity */
.highlight .ne {
color: #D2413A;
font-weight: bold;
}
/* Name.Exception */
.highlight .nf {
color: #61afef;
}
/* Name.Function */
.highlight .nl {
color: #a0a000;
}
/* Name.Label */
.highlight .nn {
color: #61AFEF;
font-weight: bold;
}
/* Name.Namespace */
.highlight .nt {
color: #BE74D5;
font-weight: bold;
}
/* Name.Tag */
.highlight .nv {
color: #dfc06f;
}
/* Name.Variable */
.highlight .ow {
color: #AA22FF;
font-weight: bold;
}
/* Operator.Word */
.highlight .w {
color: #d7dae0;
}
/* Text.Whitespace */
.highlight .mf {
color: #d19a66;
}
/* Literal.Number.Float */
.highlight .mh {
color: #d19a66;
}
/* Literal.Number.Hex */
.highlight .mi {
color: #d19a66;
}
/* Literal.Number.Integer */
.highlight .mo {
color: #d19a66;
}
/* Literal.Number.Oct */
.highlight .sb {
color: #86c372;
}
/* Literal.String.Backtick */
.highlight .sc {
color: #86c372;
}
/* Literal.String.Char */
.highlight .sd {
color: #86C372;
font-style: italic;
}
/* Literal.String.Doc */
.highlight .s2 {
color: #86c372;
}
/* Literal.String.Double */
.highlight .se {
color: #BB6622;
font-weight: bold;
}
/* Literal.String.Escape */
.highlight .sh {
color: #86c372;
}
/* Literal.String.Heredoc */
.highlight .si {
color: #BB6688;
font-weight: bold;
}
/* Literal.String.Interpol */
.highlight .sx {
color: #be74d5;
}
/* Literal.String.Other */
.highlight .sr {
color: #bb6688;
}
/* Literal.String.Regex */
.highlight .s1 {
color: #86c372;
}
/* Literal.String.Single */
.highlight .ss {
color: #dfc06f;
}
/* Literal.String.Symbol */
.highlight .bp {
color: #be74d5;
}
/* Name.Builtin.Pseudo */
.highlight .vc {
color: #dfc06f;
}
/* Name.Variable.Class */
.highlight .vg {
color: #dfc06f;
}
/* Name.Variable.Global */
.highlight .vi {
color: #dfc06f;
}
/* Name.Variable.Instance */
.highlight .il {
color: #d19a66;
}
/* Literal.Number.Integer.Long */
.highlight .lineno {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
cursor: default;
color: #556366;
}
.highlight .lineno::selection {
background: transparent;
/* WebKit/Blink Browsers */
}
.highlight .lineno::-moz-selection {
background: transparent;
/* Gecko Browsers */
}
.highlight pre {
background-color: #282C34;
color: #D7DAE0;
border: none;
margin-bottom: 25px;
font-size: 15px;
padding: 20px 10px;
}
.highlight {
font-weight: 700;
}
.table > tbody > tr > td,
.table > tbody > tr > th {
vertical-align: middle !important;
}
/*Global*/
body {
background: #1d1f21 none !important;
color: #D5D8D7 !important;
}
a {
color: #41a2ce !important;
text-decoration: none !important;
}
a:hover {
color: #5F89AC !important;
}
input,
button,
textarea,
select {
border: 1px solid #282a2e !important;
background-color: #444 !important;
color: #BBB !important;
}
input:focus,
button:focus,
textarea:focus,
select:focus {
border: 1px solid #C5C8C6 !important;
box-shadow: initial !important;
}
div#advanced-search-container div#categories label {
background: none;
border: 1px solid #282a2e;
}
ul.nav li a {
border: 0 !important;
border-bottom: 1px solid #4d3f43 !important;
}
#categories *,
.modal-wrapper * {
background: #1d1f21 none !important;
color: #D5D8D7 !important;
}
#categories * {
border: 1px solid #3d3f43 !important;
}
#categories *:checked + label {
border-bottom: 4px solid #3d9f94 !important;
}
.result-content,
.result-source,
.result-format {
color: #B5B8B7 !important;
}
.external-link {
color: #35B887 !important;
}
.table-striped tr td,
.table-striped tr th {
border-color: #4d3f43 !important;
}
.highlight {
background: #333333 !important;
}
/*nav*/
.navbar {
background: #1d1f21 none;
border: none;
}
.navbar .active,
.menu {
background: none !important;
}
.label-default {
background: none;
color: #BBB;
}
.navbar-default .navbar-nav > .active > a,
.navbar-default .navbar-nav > .active > a:hover,
.navbar-default .navbar-nav > .active > a:focus,
.nav-tabs.nav-justified > .active > a {
background-color: #282a2e !important;
}
/*Search Page*/
.result-default:hover,
.result-code:hover,
.result-torrent:hover,
.result-videos:hover,
.result-map:hover {
background-color: #222426;
}
/*buttons*/
.btn {
color: #BBB;
background-color: #444 ;
border: 1px solid #282a2e;
}
.btn:hover {
color: #444 !important;
background-color: #BBB !important;
}
.btn-primary.active {
color: #C5C8C6;
background-color: #5F89AC;
border-color: #5F89AC;
}
/*Right Pannels*/
.panel {
border: 1px solid #111;
background: none;
}
.panel-heading {
color: #C5C8C6 !important;
background: #282a2e !important;
border-bottom: none;
}
.panel-body {
color: #C5C8C6 !important;
background: #1d1f21 !important;
border-color: #111 !important;
}
p.btn.btn-default {
background: none;
}
.table-striped > tbody > tr:nth-child(odd) > td,
.table-striped > tbody > tr:nth-child(odd) > th,
.table-striped > thead > tr:nth-child(odd) > th {
background: #2d2f32 none !important;
color: #D5D8D7 !important;
}
.label-success {
background: #1d6f42 none !important;
}
.label-danger {
background: #ad1f12 none !important;
}
.searx-navbar {
background: #333334;
height: 2.3rem;
font-size: 1.3rem;
line-height: 1.3rem;
padding: 0.5rem;
font-weight: bold;
margin-bottom: 0.8rem;
}
.searx-navbar a,
.searx-navbar a:hover {
margin-right: 2.0rem;
color: white;
text-decoration: none;
}
.searx-navbar .instance a {
color: #01d7d4;
margin-left: 2.0rem;
}
#main-logo {
margin-top: 20vh;
margin-bottom: 25px;
}
#main-logo > img {
max-width: 350px;
width: 80%;
}
.onoffswitch-inner:before,
.onoffswitch-inner:after {
background: #1d1f21 none !important;
}
.onoffswitch-switch,
.onoffswitch-label {
border: 2px solid #3d3f43 !important;
}
.nav > li > a:hover,
.nav > li > a:focus {
background-color: #3d3f43 !important;
}
/*Images search*/
.img-thumbnail,
.thumbnail {
padding: 0px;
line-height: 1.42857143;
background: none;
border: none;
}
.modal-content {
background: #1d1f21 none !important;
}
/*Preferences*/
.table > thead > tr > td.danger,
.table > tbody > tr > td.danger,
.table > tfoot > tr > td.danger,
.table > thead > tr > th.danger,
.table > tbody > tr > th.danger,
.table > tfoot > tr > th.danger,
.table > thead > tr.danger > td,
.table > tbody > tr.danger > td,
.table > tfoot > tr.danger > td,
.table > thead > tr.danger > th,
.table > tbody > tr.danger > th,
.table > tfoot > tr.danger > th {
background: rgba(240, 0, 0, 0.56) !important;
color: #C5C8C6 !important;
}
.table-hover > tbody > tr > td.danger:hover,
.table-hover > tbody > tr > th.danger:hover,
.table-hover > tbody > tr.danger:hover > td,
.table-hover > tbody > tr:hover > .danger,
.table-hover > tbody > tr.danger:hover > th {
background: rgba(237, 59, 59, 0.61) !important;
color: #C5C8C6 !important;
}
.table-hover > tbody > tr:hover > td,
.table-hover > tbody > tr:hover > th {
background: #66696e !important;
}
.btn-success {
color: #C5C8C6;
background: #449d44;
}
.btn-danger {
color: #C5C8C6;
background: #d9534f;
}
.well {
background: #444;
border-color: #282a2e;
}
.highlight {
background-color: transparent !important;
}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,562 @@
html {
position: relative;
min-height: 100%;
}
body {
/* Margin bottom by footer height */
margin-bottom: 80px;
}
.footer {
position: absolute;
bottom: 0;
width: 100%;
/* Set the fixed height of the footer here */
height: 60px;
}
input[type=checkbox]:checked + .label_hide_if_checked,
input[type=checkbox]:checked + .label_hide_if_not_checked + .label_hide_if_checked {
display: none;
}
input[type=checkbox]:not(:checked) + .label_hide_if_not_checked,
input[type=checkbox]:not(:checked) + .label_hide_if_checked + .label_hide_if_not_checked {
display: none;
}
.onoff-checkbox {
width: 15%;
}
.onoffswitch {
position: relative;
width: 110px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
}
.onoffswitch-checkbox {
display: none;
}
.onoffswitch-label {
display: block;
overflow: hidden;
cursor: pointer;
border: 2px solid #FFFFFF !important;
border-radius: 50px !important;
}
.onoffswitch-inner {
display: block;
transition: margin 0.3s ease-in 0s;
}
.onoffswitch-inner:before,
.onoffswitch-inner:after {
display: block;
float: left;
width: 50%;
height: 30px;
padding: 0;
line-height: 40px;
font-size: 20px;
box-sizing: border-box;
content: "";
background-color: #EEEEEE;
}
.onoffswitch-switch {
display: block;
width: 37px;
background-color: #00CC00;
position: absolute;
top: 0;
bottom: 0;
right: 0px;
border: 2px solid #FFFFFF !important;
border-radius: 50px !important;
transition: all 0.3s ease-in 0s;
}
.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-inner {
margin-right: 0;
}
.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-switch {
right: 71px;
background-color: #A1A1A1;
}
.result_header {
margin-bottom: 5px;
margin-top: 20px;
}
.result_header .favicon {
margin-bottom: -3px;
}
.result_header a {
vertical-align: bottom;
}
.result_header a .highlight {
font-weight: bold;
}
.result-content {
margin-top: 5px;
word-wrap: break-word;
}
.result-content .highlight {
font-weight: bold;
}
.result-default {
clear: both;
}
.result-images {
float: left !important;
height: 138px;
}
.img-thumbnail {
margin: 5px;
max-height: 128px;
}
.result-videos {
clear: both;
}
.result-torrents {
clear: both;
}
.result-map {
clear: both;
}
.result-code {
clear: both;
}
.suggestion_item {
margin: 2px 5px;
max-width: 100%;
}
.suggestion_item .btn {
max-width: 100%;
white-space: normal;
word-wrap: break-word;
text-align: left;
}
.result_download {
margin-right: 5px;
}
#pagination {
margin-top: 30px;
padding-bottom: 50px;
}
.label-default {
color: #AAA;
background: #FFF;
}
.result .text-muted small {
word-wrap: break-word;
}
.modal-wrapper {
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
}
.modal-wrapper {
background-clip: padding-box;
background-color: #fff;
border: 1px solid rgba(0, 0, 0, 0.2);
border-radius: 6px;
box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);
outline: 0 none;
position: relative;
}
.infobox .infobox_part {
margin-bottom: 20px;
word-wrap: break-word;
table-layout: fixed;
}
.infobox .infobox_part:last-child {
margin-bottom: 0;
}
.search_categories,
#categories {
text-transform: capitalize;
margin-bottom: 1.5rem;
margin-top: 1.5rem;
display: flex;
flex-wrap: wrap;
align-content: stretch;
}
.search_categories label,
#categories label,
.search_categories .input-group-addon,
#categories .input-group-addon {
flex-grow: 1;
flex-basis: auto;
font-size: 1.3rem;
font-weight: normal;
background-color: white;
border: #DDD 1px solid;
border-right: none;
color: #333;
padding-bottom: 0.8rem;
padding-top: 0.8rem;
text-align: center;
min-width: 50px;
}
.search_categories label:last-child,
#categories label:last-child,
.search_categories .input-group-addon:last-child,
#categories .input-group-addon:last-child {
border-right: #DDD 1px solid;
}
.search_categories input[type="checkbox"]:checked + label,
#categories input[type="checkbox"]:checked + label {
color: black;
font-weight: bold;
background-color: #EEE;
}
#advanced-search-container {
display: none;
text-align: center;
margin-bottom: 1rem;
clear: both;
}
#advanced-search-container label,
#advanced-search-container .input-group-addon {
font-size: 1.3rem;
font-weight: normal;
background-color: white;
border: #DDD 1px solid;
border-right: none;
color: #333;
padding-bottom: 0.8rem;
padding-left: 1.2rem;
padding-right: 1.2rem;
}
#advanced-search-container label:last-child,
#advanced-search-container .input-group-addon:last-child {
border-right: #DDD 1px solid;
}
#advanced-search-container input[type="radio"] {
display: none;
}
#advanced-search-container input[type="radio"]:checked + label {
color: black;
font-weight: bold;
background-color: #EEE;
}
#check-advanced {
display: none;
}
#check-advanced:checked ~ #advanced-search-container {
display: block;
}
.advanced {
padding: 0;
margin-top: 0.3rem;
text-align: right;
}
.advanced label,
.advanced select {
cursor: pointer;
}
.cursor-text {
cursor: text !important;
}
.cursor-pointer {
cursor: pointer !important;
}
.highlight .hll {
background-color: #ffffcc;
}
.highlight {
background: #f8f8f8;
}
.highlight .c {
color: #408080;
font-style: italic;
}
/* Comment */
.highlight .err {
border: 1px solid #ff0000;
}
/* Error */
.highlight .k {
color: #008000;
font-weight: bold;
}
/* Keyword */
.highlight .o {
color: #666666;
}
/* Operator */
.highlight .cm {
color: #408080;
font-style: italic;
}
/* Comment.Multiline */
.highlight .cp {
color: #bc7a00;
}
/* Comment.Preproc */
.highlight .c1 {
color: #408080;
font-style: italic;
}
/* Comment.Single */
.highlight .cs {
color: #408080;
font-style: italic;
}
/* Comment.Special */
.highlight .gd {
color: #a00000;
}
/* Generic.Deleted */
.highlight .ge {
font-style: italic;
}
/* Generic.Emph */
.highlight .gr {
color: #ff0000;
}
/* Generic.Error */
.highlight .gh {
color: #000080;
font-weight: bold;
}
/* Generic.Heading */
.highlight .gi {
color: #00a000;
}
/* Generic.Inserted */
.highlight .go {
color: #888888;
}
/* Generic.Output */
.highlight .gp {
color: #000080;
font-weight: bold;
}
/* Generic.Prompt */
.highlight .gs {
font-weight: bold;
}
/* Generic.Strong */
.highlight .gu {
color: #800080;
font-weight: bold;
}
/* Generic.Subheading */
.highlight .gt {
color: #0044dd;
}
/* Generic.Traceback */
.highlight .kc {
color: #008000;
font-weight: bold;
}
/* Keyword.Constant */
.highlight .kd {
color: #008000;
font-weight: bold;
}
/* Keyword.Declaration */
.highlight .kn {
color: #008000;
font-weight: bold;
}
/* Keyword.Namespace */
.highlight .kp {
color: #008000;
}
/* Keyword.Pseudo */
.highlight .kr {
color: #008000;
font-weight: bold;
}
/* Keyword.Reserved */
.highlight .kt {
color: #b00040;
}
/* Keyword.Type */
.highlight .m {
color: #666666;
}
/* Literal.Number */
.highlight .s {
color: #ba2121;
}
/* Literal.String */
.highlight .na {
color: #7d9029;
}
/* Name.Attribute */
.highlight .nb {
color: #008000;
}
/* Name.Builtin */
.highlight .nc {
color: #0000FF;
font-weight: bold;
}
/* Name.Class */
.highlight .no {
color: #880000;
}
/* Name.Constant */
.highlight .nd {
color: #aa22ff;
}
/* Name.Decorator */
.highlight .ni {
color: #999999;
font-weight: bold;
}
/* Name.Entity */
.highlight .ne {
color: #D2413A;
font-weight: bold;
}
/* Name.Exception */
.highlight .nf {
color: #0000ff;
}
/* Name.Function */
.highlight .nl {
color: #a0a000;
}
/* Name.Label */
.highlight .nn {
color: #0000FF;
font-weight: bold;
}
/* Name.Namespace */
.highlight .nt {
color: #008000;
font-weight: bold;
}
/* Name.Tag */
.highlight .nv {
color: #19177c;
}
/* Name.Variable */
.highlight .ow {
color: #AA22FF;
font-weight: bold;
}
/* Operator.Word */
.highlight .w {
color: #bbbbbb;
}
/* Text.Whitespace */
.highlight .mf {
color: #666666;
}
/* Literal.Number.Float */
.highlight .mh {
color: #666666;
}
/* Literal.Number.Hex */
.highlight .mi {
color: #666666;
}
/* Literal.Number.Integer */
.highlight .mo {
color: #666666;
}
/* Literal.Number.Oct */
.highlight .sb {
color: #ba2121;
}
/* Literal.String.Backtick */
.highlight .sc {
color: #ba2121;
}
/* Literal.String.Char */
.highlight .sd {
color: #BA2121;
font-style: italic;
}
/* Literal.String.Doc */
.highlight .s2 {
color: #ba2121;
}
/* Literal.String.Double */
.highlight .se {
color: #BB6622;
font-weight: bold;
}
/* Literal.String.Escape */
.highlight .sh {
color: #ba2121;
}
/* Literal.String.Heredoc */
.highlight .si {
color: #BB6688;
font-weight: bold;
}
/* Literal.String.Interpol */
.highlight .sx {
color: #008000;
}
/* Literal.String.Other */
.highlight .sr {
color: #bb6688;
}
/* Literal.String.Regex */
.highlight .s1 {
color: #ba2121;
}
/* Literal.String.Single */
.highlight .ss {
color: #19177c;
}
/* Literal.String.Symbol */
.highlight .bp {
color: #008000;
}
/* Name.Builtin.Pseudo */
.highlight .vc {
color: #19177c;
}
/* Name.Variable.Class */
.highlight .vg {
color: #19177c;
}
/* Name.Variable.Global */
.highlight .vi {
color: #19177c;
}
/* Name.Variable.Instance */
.highlight .il {
color: #666666;
}
/* Literal.Number.Integer.Long */
.highlight .lineno {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
cursor: default;
}
.highlight .lineno::selection {
background: transparent;
/* WebKit/Blink Browsers */
}
.highlight .lineno::-moz-selection {
background: transparent;
/* Gecko Browsers */
}
.searx-navbar {
background: #eee;
color: #aaa;
height: 2.3rem;
font-size: 1.3rem;
line-height: 1.3rem;
padding: 0.5rem;
font-weight: bold;
margin-bottom: 1.3rem;
}
.searx-navbar a,
.searx-navbar a:hover {
margin-right: 2.0rem;
text-decoration: none;
}
.searx-navbar .instance a {
color: #444;
margin-left: 2.0rem;
}
.table > tbody > tr > td,
.table > tbody > tr > th {
vertical-align: middle !important;
}

View file

@ -24,7 +24,7 @@ module.exports = function(grunt) {
jshint: {
files: ['gruntfile.js', 'js/searx_src/*.js'],
options: {
reporterOutput: "",
reporterOutput: "",
// options here to override JSHint defaults
globals: {
jQuery: true,
@ -55,7 +55,7 @@ module.exports = function(grunt) {
"css/logicodev-dark.min.css": "less/logicodev-dark/oscar.less"}
},
/*
// built with ./manage.sh styles
// built with ./manage.sh styles
bootstrap: {
options: {
paths: ["less/bootstrap"],
@ -90,7 +90,7 @@ module.exports = function(grunt) {
grunt.registerTask('test', ['jshint']);
grunt.registerTask('default', ['jshint', 'concat', 'uglify', 'less']);
grunt.registerTask('styles', ['less']);
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View file

@ -0,0 +1,356 @@
/**
* 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>
*/
requirejs.config({
baseUrl: './static/themes/oscar/js',
paths: {
app: '../app'
}
});
;/**
* 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) 2019 by Alexandre Flament
*/
window.searx = (function(d) {
'use strict';
// add data- properties
var script = d.currentScript || (function() {
var scripts = d.getElementsByTagName('script');
return scripts[scripts.length - 1];
})();
return {
autocompleter: script.getAttribute('data-autocompleter') === 'true',
method: script.getAttribute('data-method')
};
})(document);
;/**
* 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>
*/
if(searx.autocompleter) {
searx.searchResults = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: './autocompleter?q=%QUERY'
});
searx.searchResults.initialize();
}
$(document).ready(function(){
if(searx.autocompleter) {
$('#q').typeahead(null, {
name: 'search-results',
displayKey: function(result) {
return result;
},
source: searx.searchResults.ttAdapter()
});
}
});
;/**
* 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>
*/
$(document).ready(function(){
/**
* focus element if class="autofocus" and id="q"
*/
$('#q.autofocus').focus();
/**
* select full content on click if class="select-all-on-click"
*/
$(".select-all-on-click").click(function () {
$(this).select();
});
/**
* change text during btn-collapse click if possible
*/
$('.btn-collapse').click(function() {
var btnTextCollapsed = $(this).data('btn-text-collapsed');
var btnTextNotCollapsed = $(this).data('btn-text-not-collapsed');
if(btnTextCollapsed !== '' && btnTextNotCollapsed !== '') {
if($(this).hasClass('collapsed')) {
new_html = $(this).html().replace(btnTextCollapsed, btnTextNotCollapsed);
} else {
new_html = $(this).html().replace(btnTextNotCollapsed, btnTextCollapsed);
}
$(this).html(new_html);
}
});
/**
* change text during btn-toggle click if possible
*/
$('.btn-toggle .btn').click(function() {
var btnClass = 'btn-' + $(this).data('btn-class');
var btnLabelDefault = $(this).data('btn-label-default');
var btnLabelToggled = $(this).data('btn-label-toggled');
if(btnLabelToggled !== '') {
if($(this).hasClass('btn-default')) {
new_html = $(this).html().replace(btnLabelDefault, btnLabelToggled);
} else {
new_html = $(this).html().replace(btnLabelToggled, btnLabelDefault);
}
$(this).html(new_html);
}
$(this).toggleClass(btnClass);
$(this).toggleClass('btn-default');
});
/**
* change text during btn-toggle click if possible
*/
$('.media-loader').click(function() {
var target = $(this).data('target');
var iframe_load = $(target + ' > iframe');
var srctest = iframe_load.attr('src');
if(srctest === undefined || srctest === false){
iframe_load.attr('src', iframe_load.data('src'));
}
});
/**
* Select or deselect every categories on double clic
*/
$(".btn-sm").dblclick(function() {
var btnClass = 'btn-' + $(this).data('btn-class'); // primary
if($(this).hasClass('btn-default')) {
$(".btn-sm > input").attr('checked', 'checked');
$(".btn-sm > input").prop("checked", true);
$(".btn-sm").addClass(btnClass);
$(".btn-sm").addClass('active');
$(".btn-sm").removeClass('btn-default');
} else {
$(".btn-sm > input").attr('checked', '');
$(".btn-sm > input").removeAttr('checked');
$(".btn-sm > input").checked = false;
$(".btn-sm").removeClass(btnClass);
$(".btn-sm").removeClass('active');
$(".btn-sm").addClass('btn-default');
}
});
});
;/**
* 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>
*/
$(document).ready(function(){
$(".searx_overpass_request").on( "click", function( event ) {
var overpass_url = "https://overpass-api.de/api/interpreter?data=";
var query_start = overpass_url + "[out:json][timeout:25];(";
var query_end = ");out meta;";
var osm_id = $(this).data('osm-id');
var osm_type = $(this).data('osm-type');
var result_table = $(this).data('result-table');
var result_table_loadicon = "#" + $(this).data('result-table-loadicon');
// tags which can be ignored
var osm_ignore_tags = [ "addr:city", "addr:country", "addr:housenumber", "addr:postcode", "addr:street" ];
if(osm_id && osm_type && result_table) {
result_table = "#" + result_table;
var query = null;
switch(osm_type) {
case 'node':
query = query_start + "node(" + osm_id + ");" + query_end;
break;
case 'way':
query = query_start + "way(" + osm_id + ");" + query_end;
break;
case 'relation':
query = query_start + "relation(" + osm_id + ");" + query_end;
break;
default:
break;
}
if(query) {
//alert(query);
var ajaxRequest = $.ajax( query )
.done(function( html) {
if(html && html.elements && html.elements[0]) {
var element = html.elements[0];
var newHtml = $(result_table).html();
for (var row in element.tags) {
if(element.tags.name === null || osm_ignore_tags.indexOf(row) == -1) {
newHtml += "<tr><td>" + row + "</td><td>";
switch(row) {
case "phone":
case "fax":
newHtml += "<a href=\"tel:" + element.tags[row].replace(/ /g,'') + "\">" + element.tags[row] + "</a>";
break;
case "email":
newHtml += "<a href=\"mailto:" + element.tags[row] + "\">" + element.tags[row] + "</a>";
break;
case "website":
case "url":
newHtml += "<a href=\"" + element.tags[row] + "\">" + element.tags[row] + "</a>";
break;
case "wikidata":
newHtml += "<a href=\"https://www.wikidata.org/wiki/" + element.tags[row] + "\">" + element.tags[row] + "</a>";
break;
case "wikipedia":
if(element.tags[row].indexOf(":") != -1) {
newHtml += "<a href=\"https://" + element.tags[row].substring(0,element.tags[row].indexOf(":")) + ".wikipedia.org/wiki/" + element.tags[row].substring(element.tags[row].indexOf(":")+1) + "\">" + element.tags[row] + "</a>";
break;
}
/* jshint ignore:start */
default:
/* jshint ignore:end */
newHtml += element.tags[row];
break;
}
newHtml += "</td></tr>";
}
}
$(result_table).html(newHtml);
$(result_table).removeClass('hidden');
$(result_table_loadicon).addClass('hidden');
}
})
.fail(function() {
$(result_table_loadicon).html($(result_table_loadicon).html() + "<p class=\"text-muted\">could not load data!</p>");
});
}
}
// this event occour only once per element
$( this ).off( event );
});
$(".searx_init_map").on( "click", function( event ) {
var leaflet_target = $(this).data('leaflet-target');
var map_lon = $(this).data('map-lon');
var map_lat = $(this).data('map-lat');
var map_zoom = $(this).data('map-zoom');
var map_boundingbox = $(this).data('map-boundingbox');
var map_geojson = $(this).data('map-geojson');
require(['leaflet-0.7.3.min'], function(leaflet) {
if(map_boundingbox) {
southWest = L.latLng(map_boundingbox[0], map_boundingbox[2]);
northEast = L.latLng(map_boundingbox[1], map_boundingbox[3]);
map_bounds = L.latLngBounds(southWest, northEast);
}
// TODO hack
// change default imagePath
L.Icon.Default.imagePath = "./static/themes/oscar/img/map";
// init map
var map = L.map(leaflet_target);
// create the tile layer with correct attribution
var osmMapnikUrl='https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
var osmMapnikAttrib='Map data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors';
var osmMapnik = new L.TileLayer(osmMapnikUrl, {minZoom: 1, maxZoom: 19, attribution: osmMapnikAttrib});
var osmWikimediaUrl='https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png';
var osmWikimediaAttrib = 'Wikimedia maps beta | Maps data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors';
var osmWikimedia = new L.TileLayer(osmWikimediaUrl, {minZoom: 1, maxZoom: 19, attribution: osmWikimediaAttrib});
// init map view
if(map_bounds) {
// TODO hack: https://github.com/Leaflet/Leaflet/issues/2021
setTimeout(function () {
map.fitBounds(map_bounds, {
maxZoom:17
});
}, 0);
} else if (map_lon && map_lat) {
if(map_zoom)
map.setView(new L.LatLng(map_lat, map_lon),map_zoom);
else
map.setView(new L.LatLng(map_lat, map_lon),8);
}
map.addLayer(osmMapnik);
var baseLayers = {
"OSM Mapnik": osmMapnik/*,
"OSM Wikimedia": osmWikimedia*/
};
L.control.layers(baseLayers).addTo(map);
if(map_geojson)
L.geoJson(map_geojson).addTo(map);
/*else if(map_bounds)
L.rectangle(map_bounds, {color: "#ff7800", weight: 3, fill:false}).addTo(map);*/
});
// this event occour only once per element
$( this ).off( event );
});
});

View file

@ -1,2 +1,2 @@
/*! oscar/searx.min.js | 06-10-2017 | https://github.com/asciimoo/searx */
requirejs.config({baseUrl:"./static/themes/oscar/js",paths:{app:"../app"}}),searx.autocompleter&&(searx.searchResults=new Bloodhound({datumTokenizer:Bloodhound.tokenizers.obj.whitespace("value"),queryTokenizer:Bloodhound.tokenizers.whitespace,remote:"./autocompleter?q=%QUERY"}),searx.searchResults.initialize()),$(document).ready(function(){searx.autocompleter&&$("#q").typeahead(null,{name:"search-results",displayKey:function(a){return a},source:searx.searchResults.ttAdapter()})}),$(document).ready(function(){$("#q.autofocus").focus(),$(".select-all-on-click").click(function(){$(this).select()}),$(".btn-collapse").click(function(){var a=$(this).data("btn-text-collapsed"),b=$(this).data("btn-text-not-collapsed");""!==a&&""!==b&&($(this).hasClass("collapsed")?new_html=$(this).html().replace(a,b):new_html=$(this).html().replace(b,a),$(this).html(new_html))}),$(".btn-toggle .btn").click(function(){var a="btn-"+$(this).data("btn-class"),b=$(this).data("btn-label-default"),c=$(this).data("btn-label-toggled");""!==c&&($(this).hasClass("btn-default")?new_html=$(this).html().replace(b,c):new_html=$(this).html().replace(c,b),$(this).html(new_html)),$(this).toggleClass(a),$(this).toggleClass("btn-default")}),$(".media-loader").click(function(){var a=$(this).data("target"),b=$(a+" > iframe"),c=b.attr("src");void 0!==c&&c!==!1||b.attr("src",b.data("src"))}),$(".btn-sm").dblclick(function(){var a="btn-"+$(this).data("btn-class");$(this).hasClass("btn-default")?($(".btn-sm > input").attr("checked","checked"),$(".btn-sm > input").prop("checked",!0),$(".btn-sm").addClass(a),$(".btn-sm").addClass("active"),$(".btn-sm").removeClass("btn-default")):($(".btn-sm > input").attr("checked",""),$(".btn-sm > input").removeAttr("checked"),$(".btn-sm > input").checked=!1,$(".btn-sm").removeClass(a),$(".btn-sm").removeClass("active"),$(".btn-sm").addClass("btn-default"))})}),$(document).ready(function(){$(".searx_overpass_request").on("click",function(a){var b="https://overpass-api.de/api/interpreter?data=",c=b+"[out:json][timeout:25];(",d=");out meta;",e=$(this).data("osm-id"),f=$(this).data("osm-type"),g=$(this).data("result-table"),h="#"+$(this).data("result-table-loadicon"),i=["addr:city","addr:country","addr:housenumber","addr:postcode","addr:street"];if(e&&f&&g){g="#"+g;var j=null;switch(f){case"node":j=c+"node("+e+");"+d;break;case"way":j=c+"way("+e+");"+d;break;case"relation":j=c+"relation("+e+");"+d}if(j){$.ajax(j).done(function(a){if(a&&a.elements&&a.elements[0]){var b=a.elements[0],c=$(g).html();for(var d in b.tags)if(null===b.tags.name||i.indexOf(d)==-1){switch(c+="<tr><td>"+d+"</td><td>",d){case"phone":case"fax":c+='<a href="tel:'+b.tags[d].replace(/ /g,"")+'">'+b.tags[d]+"</a>";break;case"email":c+='<a href="mailto:'+b.tags[d]+'">'+b.tags[d]+"</a>";break;case"website":case"url":c+='<a href="'+b.tags[d]+'">'+b.tags[d]+"</a>";break;case"wikidata":c+='<a href="https://www.wikidata.org/wiki/'+b.tags[d]+'">'+b.tags[d]+"</a>";break;case"wikipedia":if(b.tags[d].indexOf(":")!=-1){c+='<a href="https://'+b.tags[d].substring(0,b.tags[d].indexOf(":"))+".wikipedia.org/wiki/"+b.tags[d].substring(b.tags[d].indexOf(":")+1)+'">'+b.tags[d]+"</a>";break}default:c+=b.tags[d]}c+="</td></tr>"}$(g).html(c),$(g).removeClass("hidden"),$(h).addClass("hidden")}}).fail(function(){$(h).html($(h).html()+'<p class="text-muted">could not load data!</p>')})}}$(this).off(a)}),$(".searx_init_map").on("click",function(a){var b=$(this).data("leaflet-target"),c=$(this).data("map-lon"),d=$(this).data("map-lat"),e=$(this).data("map-zoom"),f=$(this).data("map-boundingbox"),g=$(this).data("map-geojson");require(["leaflet-0.7.3.min"],function(a){f&&(southWest=L.latLng(f[0],f[2]),northEast=L.latLng(f[1],f[3]),map_bounds=L.latLngBounds(southWest,northEast)),L.Icon.Default.imagePath="./static/themes/oscar/img/map";var h=L.map(b),i="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",j='Map data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors',k=new L.TileLayer(i,{minZoom:1,maxZoom:19,attribution:j}),l="https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png",m='Wikimedia maps beta | Maps data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors';new L.TileLayer(l,{minZoom:1,maxZoom:19,attribution:m});map_bounds?setTimeout(function(){h.fitBounds(map_bounds,{maxZoom:17})},0):c&&d&&(e?h.setView(new L.LatLng(d,c),e):h.setView(new L.LatLng(d,c),8)),h.addLayer(k);var n={"OSM Mapnik":k};L.control.layers(n).addTo(h),g&&L.geoJson(g).addTo(h)}),$(this).off(a)})});
/*! oscar/searx.min.js | 06-08-2019 | https://github.com/asciimoo/searx */
requirejs.config({baseUrl:"./static/themes/oscar/js",paths:{app:"../app"}}),window.searx=function(a){"use strict";var b=a.currentScript||function(){var b=a.getElementsByTagName("script");return b[b.length-1]}();return{autocompleter:"true"===b.getAttribute("data-autocompleter"),method:b.getAttribute("data-method")}}(document),searx.autocompleter&&(searx.searchResults=new Bloodhound({datumTokenizer:Bloodhound.tokenizers.obj.whitespace("value"),queryTokenizer:Bloodhound.tokenizers.whitespace,remote:"./autocompleter?q=%QUERY"}),searx.searchResults.initialize()),$(document).ready(function(){searx.autocompleter&&$("#q").typeahead(null,{name:"search-results",displayKey:function(a){return a},source:searx.searchResults.ttAdapter()})}),$(document).ready(function(){$("#q.autofocus").focus(),$(".select-all-on-click").click(function(){$(this).select()}),$(".btn-collapse").click(function(){var a=$(this).data("btn-text-collapsed"),b=$(this).data("btn-text-not-collapsed");""!==a&&""!==b&&($(this).hasClass("collapsed")?new_html=$(this).html().replace(a,b):new_html=$(this).html().replace(b,a),$(this).html(new_html))}),$(".btn-toggle .btn").click(function(){var a="btn-"+$(this).data("btn-class"),b=$(this).data("btn-label-default"),c=$(this).data("btn-label-toggled");""!==c&&($(this).hasClass("btn-default")?new_html=$(this).html().replace(b,c):new_html=$(this).html().replace(c,b),$(this).html(new_html)),$(this).toggleClass(a),$(this).toggleClass("btn-default")}),$(".media-loader").click(function(){var a=$(this).data("target"),b=$(a+" > iframe"),c=b.attr("src");void 0!==c&&!1!==c||b.attr("src",b.data("src"))}),$(".btn-sm").dblclick(function(){var a="btn-"+$(this).data("btn-class");$(this).hasClass("btn-default")?($(".btn-sm > input").attr("checked","checked"),$(".btn-sm > input").prop("checked",!0),$(".btn-sm").addClass(a),$(".btn-sm").addClass("active"),$(".btn-sm").removeClass("btn-default")):($(".btn-sm > input").attr("checked",""),$(".btn-sm > input").removeAttr("checked"),$(".btn-sm > input").checked=!1,$(".btn-sm").removeClass(a),$(".btn-sm").removeClass("active"),$(".btn-sm").addClass("btn-default"))})}),$(document).ready(function(){$(".searx_overpass_request").on("click",function(a){var b="https://overpass-api.de/api/interpreter?data=",c=b+"[out:json][timeout:25];(",d=");out meta;",e=$(this).data("osm-id"),f=$(this).data("osm-type"),g=$(this).data("result-table"),h="#"+$(this).data("result-table-loadicon"),i=["addr:city","addr:country","addr:housenumber","addr:postcode","addr:street"];if(e&&f&&g){g="#"+g;var j=null;switch(f){case"node":j=c+"node("+e+");"+d;break;case"way":j=c+"way("+e+");"+d;break;case"relation":j=c+"relation("+e+");"+d}if(j){$.ajax(j).done(function(a){if(a&&a.elements&&a.elements[0]){var b=a.elements[0],c=$(g).html();for(var d in b.tags)if(null===b.tags.name||-1==i.indexOf(d)){switch(c+="<tr><td>"+d+"</td><td>",d){case"phone":case"fax":c+='<a href="tel:'+b.tags[d].replace(/ /g,"")+'">'+b.tags[d]+"</a>";break;case"email":c+='<a href="mailto:'+b.tags[d]+'">'+b.tags[d]+"</a>";break;case"website":case"url":c+='<a href="'+b.tags[d]+'">'+b.tags[d]+"</a>";break;case"wikidata":c+='<a href="https://www.wikidata.org/wiki/'+b.tags[d]+'">'+b.tags[d]+"</a>";break;case"wikipedia":if(-1!=b.tags[d].indexOf(":")){c+='<a href="https://'+b.tags[d].substring(0,b.tags[d].indexOf(":"))+".wikipedia.org/wiki/"+b.tags[d].substring(b.tags[d].indexOf(":")+1)+'">'+b.tags[d]+"</a>";break}default:c+=b.tags[d]}c+="</td></tr>"}$(g).html(c),$(g).removeClass("hidden"),$(h).addClass("hidden")}}).fail(function(){$(h).html($(h).html()+'<p class="text-muted">could not load data!</p>')})}}$(this).off(a)}),$(".searx_init_map").on("click",function(a){var b=$(this).data("leaflet-target"),c=$(this).data("map-lon"),d=$(this).data("map-lat"),e=$(this).data("map-zoom"),f=$(this).data("map-boundingbox"),g=$(this).data("map-geojson");require(["leaflet-0.7.3.min"],function(a){f&&(southWest=L.latLng(f[0],f[2]),northEast=L.latLng(f[1],f[3]),map_bounds=L.latLngBounds(southWest,northEast)),L.Icon.Default.imagePath="./static/themes/oscar/img/map";var h=L.map(b),i="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",j='Map data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors',k=new L.TileLayer(i,{minZoom:1,maxZoom:19,attribution:j}),l="https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png",m='Wikimedia maps beta | Maps data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors';new L.TileLayer(l,{minZoom:1,maxZoom:19,attribution:m});map_bounds?setTimeout(function(){h.fitBounds(map_bounds,{maxZoom:17})},0):c&&d&&(e?h.setView(new L.LatLng(d,c),e):h.setView(new L.LatLng(d,c),8)),h.addLayer(k);var n={"OSM Mapnik":k};L.control.layers(n).addTo(h),g&&L.geoJson(g).addTo(h)}),$(this).off(a)})});

View file

@ -1,23 +1,23 @@
/**
* 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>
*/
requirejs.config({
baseUrl: './static/themes/oscar/js',
paths: {
app: '../app'
}
});
/**
* 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>
*/
requirejs.config({
baseUrl: './static/themes/oscar/js',
paths: {
app: '../app'
}
});

View file

@ -0,0 +1,30 @@
/**
* 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) 2019 by Alexandre Flament
*/
window.searx = (function(d) {
'use strict';
// add data- properties
var script = d.currentScript || (function() {
var scripts = d.getElementsByTagName('script');
return scripts[scripts.length - 1];
})();
return {
autocompleter: script.getAttribute('data-autocompleter') === 'true',
method: script.getAttribute('data-method')
};
})(document);

View file

@ -1,37 +1,37 @@
/**
* 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>
*/
if(searx.autocompleter) {
searx.searchResults = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: './autocompleter?q=%QUERY'
});
searx.searchResults.initialize();
}
$(document).ready(function(){
if(searx.autocompleter) {
$('#q').typeahead(null, {
name: 'search-results',
displayKey: function(result) {
return result;
},
source: searx.searchResults.ttAdapter()
});
}
});
/**
* 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>
*/
if(searx.autocompleter) {
searx.searchResults = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: './autocompleter?q=%QUERY'
});
searx.searchResults.initialize();
}
$(document).ready(function(){
if(searx.autocompleter) {
$('#q').typeahead(null, {
name: 'search-results',
displayKey: function(result) {
return result;
},
source: searx.searchResults.ttAdapter()
});
}
});

View file

@ -1,99 +1,99 @@
/**
* 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>
*/
$(document).ready(function(){
/**
* focus element if class="autofocus" and id="q"
*/
$('#q.autofocus').focus();
/**
* select full content on click if class="select-all-on-click"
*/
$(".select-all-on-click").click(function () {
$(this).select();
});
/**
* change text during btn-collapse click if possible
*/
$('.btn-collapse').click(function() {
var btnTextCollapsed = $(this).data('btn-text-collapsed');
var btnTextNotCollapsed = $(this).data('btn-text-not-collapsed');
if(btnTextCollapsed !== '' && btnTextNotCollapsed !== '') {
if($(this).hasClass('collapsed')) {
new_html = $(this).html().replace(btnTextCollapsed, btnTextNotCollapsed);
} else {
new_html = $(this).html().replace(btnTextNotCollapsed, btnTextCollapsed);
}
$(this).html(new_html);
}
});
/**
* change text during btn-toggle click if possible
*/
$('.btn-toggle .btn').click(function() {
var btnClass = 'btn-' + $(this).data('btn-class');
var btnLabelDefault = $(this).data('btn-label-default');
var btnLabelToggled = $(this).data('btn-label-toggled');
if(btnLabelToggled !== '') {
if($(this).hasClass('btn-default')) {
new_html = $(this).html().replace(btnLabelDefault, btnLabelToggled);
} else {
new_html = $(this).html().replace(btnLabelToggled, btnLabelDefault);
}
$(this).html(new_html);
}
$(this).toggleClass(btnClass);
$(this).toggleClass('btn-default');
});
/**
* change text during btn-toggle click if possible
*/
$('.media-loader').click(function() {
var target = $(this).data('target');
var iframe_load = $(target + ' > iframe');
var srctest = iframe_load.attr('src');
if(srctest === undefined || srctest === false){
iframe_load.attr('src', iframe_load.data('src'));
}
});
/**
* Select or deselect every categories on double clic
*/
$(".btn-sm").dblclick(function() {
var btnClass = 'btn-' + $(this).data('btn-class'); // primary
if($(this).hasClass('btn-default')) {
$(".btn-sm > input").attr('checked', 'checked');
$(".btn-sm > input").prop("checked", true);
$(".btn-sm").addClass(btnClass);
$(".btn-sm").addClass('active');
$(".btn-sm").removeClass('btn-default');
} else {
$(".btn-sm > input").attr('checked', '');
$(".btn-sm > input").removeAttr('checked');
$(".btn-sm > input").checked = false;
$(".btn-sm").removeClass(btnClass);
$(".btn-sm").removeClass('active');
$(".btn-sm").addClass('btn-default');
}
});
});
/**
* 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>
*/
$(document).ready(function(){
/**
* focus element if class="autofocus" and id="q"
*/
$('#q.autofocus').focus();
/**
* select full content on click if class="select-all-on-click"
*/
$(".select-all-on-click").click(function () {
$(this).select();
});
/**
* change text during btn-collapse click if possible
*/
$('.btn-collapse').click(function() {
var btnTextCollapsed = $(this).data('btn-text-collapsed');
var btnTextNotCollapsed = $(this).data('btn-text-not-collapsed');
if(btnTextCollapsed !== '' && btnTextNotCollapsed !== '') {
if($(this).hasClass('collapsed')) {
new_html = $(this).html().replace(btnTextCollapsed, btnTextNotCollapsed);
} else {
new_html = $(this).html().replace(btnTextNotCollapsed, btnTextCollapsed);
}
$(this).html(new_html);
}
});
/**
* change text during btn-toggle click if possible
*/
$('.btn-toggle .btn').click(function() {
var btnClass = 'btn-' + $(this).data('btn-class');
var btnLabelDefault = $(this).data('btn-label-default');
var btnLabelToggled = $(this).data('btn-label-toggled');
if(btnLabelToggled !== '') {
if($(this).hasClass('btn-default')) {
new_html = $(this).html().replace(btnLabelDefault, btnLabelToggled);
} else {
new_html = $(this).html().replace(btnLabelToggled, btnLabelDefault);
}
$(this).html(new_html);
}
$(this).toggleClass(btnClass);
$(this).toggleClass('btn-default');
});
/**
* change text during btn-toggle click if possible
*/
$('.media-loader').click(function() {
var target = $(this).data('target');
var iframe_load = $(target + ' > iframe');
var srctest = iframe_load.attr('src');
if(srctest === undefined || srctest === false){
iframe_load.attr('src', iframe_load.data('src'));
}
});
/**
* Select or deselect every categories on double clic
*/
$(".btn-sm").dblclick(function() {
var btnClass = 'btn-' + $(this).data('btn-class'); // primary
if($(this).hasClass('btn-default')) {
$(".btn-sm > input").attr('checked', 'checked');
$(".btn-sm > input").prop("checked", true);
$(".btn-sm").addClass(btnClass);
$(".btn-sm").addClass('active');
$(".btn-sm").removeClass('btn-default');
} else {
$(".btn-sm > input").attr('checked', '');
$(".btn-sm > input").removeAttr('checked');
$(".btn-sm > input").checked = false;
$(".btn-sm").removeClass(btnClass);
$(".btn-sm").removeClass('active');
$(".btn-sm").addClass('btn-default');
}
});
});

View file

@ -1,167 +1,167 @@
/**
* 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>
*/
$(document).ready(function(){
$(".searx_overpass_request").on( "click", function( event ) {
var overpass_url = "https://overpass-api.de/api/interpreter?data=";
var query_start = overpass_url + "[out:json][timeout:25];(";
var query_end = ");out meta;";
var osm_id = $(this).data('osm-id');
var osm_type = $(this).data('osm-type');
var result_table = $(this).data('result-table');
var result_table_loadicon = "#" + $(this).data('result-table-loadicon');
// tags which can be ignored
var osm_ignore_tags = [ "addr:city", "addr:country", "addr:housenumber", "addr:postcode", "addr:street" ];
if(osm_id && osm_type && result_table) {
result_table = "#" + result_table;
var query = null;
switch(osm_type) {
case 'node':
query = query_start + "node(" + osm_id + ");" + query_end;
break;
case 'way':
query = query_start + "way(" + osm_id + ");" + query_end;
break;
case 'relation':
query = query_start + "relation(" + osm_id + ");" + query_end;
break;
default:
break;
}
if(query) {
//alert(query);
var ajaxRequest = $.ajax( query )
.done(function( html) {
if(html && html.elements && html.elements[0]) {
var element = html.elements[0];
var newHtml = $(result_table).html();
for (var row in element.tags) {
if(element.tags.name === null || osm_ignore_tags.indexOf(row) == -1) {
newHtml += "<tr><td>" + row + "</td><td>";
switch(row) {
case "phone":
case "fax":
newHtml += "<a href=\"tel:" + element.tags[row].replace(/ /g,'') + "\">" + element.tags[row] + "</a>";
break;
case "email":
newHtml += "<a href=\"mailto:" + element.tags[row] + "\">" + element.tags[row] + "</a>";
break;
case "website":
case "url":
newHtml += "<a href=\"" + element.tags[row] + "\">" + element.tags[row] + "</a>";
break;
case "wikidata":
newHtml += "<a href=\"https://www.wikidata.org/wiki/" + element.tags[row] + "\">" + element.tags[row] + "</a>";
break;
case "wikipedia":
if(element.tags[row].indexOf(":") != -1) {
newHtml += "<a href=\"https://" + element.tags[row].substring(0,element.tags[row].indexOf(":")) + ".wikipedia.org/wiki/" + element.tags[row].substring(element.tags[row].indexOf(":")+1) + "\">" + element.tags[row] + "</a>";
break;
}
/* jshint ignore:start */
default:
/* jshint ignore:end */
newHtml += element.tags[row];
break;
}
newHtml += "</td></tr>";
}
}
$(result_table).html(newHtml);
$(result_table).removeClass('hidden');
$(result_table_loadicon).addClass('hidden');
}
})
.fail(function() {
$(result_table_loadicon).html($(result_table_loadicon).html() + "<p class=\"text-muted\">could not load data!</p>");
});
}
}
// this event occour only once per element
$( this ).off( event );
});
$(".searx_init_map").on( "click", function( event ) {
var leaflet_target = $(this).data('leaflet-target');
var map_lon = $(this).data('map-lon');
var map_lat = $(this).data('map-lat');
var map_zoom = $(this).data('map-zoom');
var map_boundingbox = $(this).data('map-boundingbox');
var map_geojson = $(this).data('map-geojson');
require(['leaflet-0.7.3.min'], function(leaflet) {
if(map_boundingbox) {
southWest = L.latLng(map_boundingbox[0], map_boundingbox[2]);
northEast = L.latLng(map_boundingbox[1], map_boundingbox[3]);
map_bounds = L.latLngBounds(southWest, northEast);
}
// TODO hack
// change default imagePath
L.Icon.Default.imagePath = "./static/themes/oscar/img/map";
// init map
var map = L.map(leaflet_target);
// create the tile layer with correct attribution
var osmMapnikUrl='https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
var osmMapnikAttrib='Map data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors';
var osmMapnik = new L.TileLayer(osmMapnikUrl, {minZoom: 1, maxZoom: 19, attribution: osmMapnikAttrib});
var osmWikimediaUrl='https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png';
var osmWikimediaAttrib = 'Wikimedia maps beta | Maps data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors';
var osmWikimedia = new L.TileLayer(osmWikimediaUrl, {minZoom: 1, maxZoom: 19, attribution: osmWikimediaAttrib});
// init map view
if(map_bounds) {
// TODO hack: https://github.com/Leaflet/Leaflet/issues/2021
setTimeout(function () {
map.fitBounds(map_bounds, {
maxZoom:17
});
}, 0);
} else if (map_lon && map_lat) {
if(map_zoom)
map.setView(new L.LatLng(map_lat, map_lon),map_zoom);
else
map.setView(new L.LatLng(map_lat, map_lon),8);
}
map.addLayer(osmMapnik);
var baseLayers = {
"OSM Mapnik": osmMapnik/*,
"OSM Wikimedia": osmWikimedia*/
};
L.control.layers(baseLayers).addTo(map);
if(map_geojson)
L.geoJson(map_geojson).addTo(map);
/*else if(map_bounds)
L.rectangle(map_bounds, {color: "#ff7800", weight: 3, fill:false}).addTo(map);*/
});
// this event occour only once per element
$( this ).off( event );
});
});
/**
* 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>
*/
$(document).ready(function(){
$(".searx_overpass_request").on( "click", function( event ) {
var overpass_url = "https://overpass-api.de/api/interpreter?data=";
var query_start = overpass_url + "[out:json][timeout:25];(";
var query_end = ");out meta;";
var osm_id = $(this).data('osm-id');
var osm_type = $(this).data('osm-type');
var result_table = $(this).data('result-table');
var result_table_loadicon = "#" + $(this).data('result-table-loadicon');
// tags which can be ignored
var osm_ignore_tags = [ "addr:city", "addr:country", "addr:housenumber", "addr:postcode", "addr:street" ];
if(osm_id && osm_type && result_table) {
result_table = "#" + result_table;
var query = null;
switch(osm_type) {
case 'node':
query = query_start + "node(" + osm_id + ");" + query_end;
break;
case 'way':
query = query_start + "way(" + osm_id + ");" + query_end;
break;
case 'relation':
query = query_start + "relation(" + osm_id + ");" + query_end;
break;
default:
break;
}
if(query) {
//alert(query);
var ajaxRequest = $.ajax( query )
.done(function( html) {
if(html && html.elements && html.elements[0]) {
var element = html.elements[0];
var newHtml = $(result_table).html();
for (var row in element.tags) {
if(element.tags.name === null || osm_ignore_tags.indexOf(row) == -1) {
newHtml += "<tr><td>" + row + "</td><td>";
switch(row) {
case "phone":
case "fax":
newHtml += "<a href=\"tel:" + element.tags[row].replace(/ /g,'') + "\">" + element.tags[row] + "</a>";
break;
case "email":
newHtml += "<a href=\"mailto:" + element.tags[row] + "\">" + element.tags[row] + "</a>";
break;
case "website":
case "url":
newHtml += "<a href=\"" + element.tags[row] + "\">" + element.tags[row] + "</a>";
break;
case "wikidata":
newHtml += "<a href=\"https://www.wikidata.org/wiki/" + element.tags[row] + "\">" + element.tags[row] + "</a>";
break;
case "wikipedia":
if(element.tags[row].indexOf(":") != -1) {
newHtml += "<a href=\"https://" + element.tags[row].substring(0,element.tags[row].indexOf(":")) + ".wikipedia.org/wiki/" + element.tags[row].substring(element.tags[row].indexOf(":")+1) + "\">" + element.tags[row] + "</a>";
break;
}
/* jshint ignore:start */
default:
/* jshint ignore:end */
newHtml += element.tags[row];
break;
}
newHtml += "</td></tr>";
}
}
$(result_table).html(newHtml);
$(result_table).removeClass('hidden');
$(result_table_loadicon).addClass('hidden');
}
})
.fail(function() {
$(result_table_loadicon).html($(result_table_loadicon).html() + "<p class=\"text-muted\">could not load data!</p>");
});
}
}
// this event occour only once per element
$( this ).off( event );
});
$(".searx_init_map").on( "click", function( event ) {
var leaflet_target = $(this).data('leaflet-target');
var map_lon = $(this).data('map-lon');
var map_lat = $(this).data('map-lat');
var map_zoom = $(this).data('map-zoom');
var map_boundingbox = $(this).data('map-boundingbox');
var map_geojson = $(this).data('map-geojson');
require(['leaflet-0.7.3.min'], function(leaflet) {
if(map_boundingbox) {
southWest = L.latLng(map_boundingbox[0], map_boundingbox[2]);
northEast = L.latLng(map_boundingbox[1], map_boundingbox[3]);
map_bounds = L.latLngBounds(southWest, northEast);
}
// TODO hack
// change default imagePath
L.Icon.Default.imagePath = "./static/themes/oscar/img/map";
// init map
var map = L.map(leaflet_target);
// create the tile layer with correct attribution
var osmMapnikUrl='https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
var osmMapnikAttrib='Map data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors';
var osmMapnik = new L.TileLayer(osmMapnikUrl, {minZoom: 1, maxZoom: 19, attribution: osmMapnikAttrib});
var osmWikimediaUrl='https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png';
var osmWikimediaAttrib = 'Wikimedia maps beta | Maps data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors';
var osmWikimedia = new L.TileLayer(osmWikimediaUrl, {minZoom: 1, maxZoom: 19, attribution: osmWikimediaAttrib});
// init map view
if(map_bounds) {
// TODO hack: https://github.com/Leaflet/Leaflet/issues/2021
setTimeout(function () {
map.fitBounds(map_bounds, {
maxZoom:17
});
}, 0);
} else if (map_lon && map_lat) {
if(map_zoom)
map.setView(new L.LatLng(map_lat, map_lon),map_zoom);
else
map.setView(new L.LatLng(map_lat, map_lon),8);
}
map.addLayer(osmMapnik);
var baseLayers = {
"OSM Mapnik": osmMapnik/*,
"OSM Wikimedia": osmWikimedia*/
};
L.control.layers(baseLayers).addTo(map);
if(map_geojson)
L.geoJson(map_geojson).addTo(map);
/*else if(map_bounds)
L.rectangle(map_bounds, {color: "#ff7800", weight: 3, fill:false}).addTo(map);*/
});
// this event occour only once per element
$( this ).off( event );
});
});

View file

@ -59,7 +59,7 @@ ul.nav li a {
border-bottom: 4px solid #3d9f94 !important;
}
.result-content {
.result-content, .result-source, .result-format {
color:#B5B8B7 !important;
}
@ -109,7 +109,7 @@ ul.nav li a {
.btn:hover {
color:#444 !important;
background-color: #BBB !important;
background-color: #BBB !important;
}
.btn-primary.active {
@ -221,7 +221,7 @@ p.btn.btn-default{
}
.table-hover > tbody > tr:hover > td, .table-hover > tbody > tr:hover > th {
background: rgb(102, 105, 110) !important;
background: rgb(102, 105, 110) !important;
}
.btn-success {

View file

@ -78,7 +78,7 @@ pre, code{
user-select: none;
cursor: default;
color: #556366;
&::selection {
background: transparent; /* WebKit/Blink Browsers */
}
@ -99,5 +99,3 @@ pre, code{
.highlight {
font-weight: 700;
}

View file

@ -30,7 +30,7 @@
table-layout: fixed;
}
.infobox_part:last-child {
margin-bottom: 0;
}

View file

@ -28,4 +28,3 @@
width: 80%;
}
}

View file

@ -27,7 +27,7 @@
}
}
.result-content {
.result-content, .result-format, .result-source {
margin-top: 2px;
margin-bottom: 0;
word-wrap: break-word;
@ -41,6 +41,16 @@
}
.result-source {
font-size: 10px;
float: left;
}
.result-format {
font-size: 10px;
float: right;
}
.external-link {
color: @dark-green;
font-size: 12px;

View file

@ -69,7 +69,7 @@
-ms-user-select: none;
user-select: none;
cursor: default;
&::selection {
background: transparent; /* WebKit/Blink Browsers */
}

View file

@ -4,7 +4,7 @@
word-wrap: break-word;
table-layout: fixed;
}
.infobox_part:last-child {
margin-bottom: 0;
}

View file

@ -2,12 +2,11 @@
"devDependencies": {
"grunt": "~0.4.5",
"grunt-contrib-uglify": "~0.6.0",
"grunt-contrib-watch" : "~0.6.1",
"grunt-contrib-concat" : "~0.5.0",
"grunt-contrib-jshint" : "~0.10.0",
"grunt-contrib-less" : "~0.11.0"
"grunt-contrib-watch": "~0.6.1",
"grunt-contrib-concat": "~0.5.0",
"grunt-contrib-jshint": "~0.10.0",
"grunt-contrib-less": "~0.11.0"
},
"scripts": {
"build": "npm install && grunt",
"start": "grunt watch",

File diff suppressed because one or more lines are too long

View file

@ -1,4 +1,4 @@
/*! searx | 14-08-2018 | https://github.com/asciimoo/searx */
/*! searx | 06-08-2019 | https://github.com/asciimoo/searx */
/*
* searx, A privacy-respecting, hackable metasearch engine
*

File diff suppressed because one or more lines are too long

View file

@ -1,4 +1,4 @@
/*! searx | 14-08-2018 | https://github.com/asciimoo/searx */
/*! searx | 06-08-2019 | https://github.com/asciimoo/searx */
/*
* searx, A privacy-respecting, hackable metasearch engine
*

File diff suppressed because one or more lines are too long

View file

@ -10,35 +10,8 @@ module.exports = function(grunt) {
tasks: ['jshint', 'concat', 'uglify', 'webfont', 'less:development', 'less:production']
}
},
concat: {
options: {
separator: ';'
},
dist: {
src: ['js/searx_src/*.js'],
dest: 'js/searx.js'
}
},
uglify: {
options: {
banner: '/*! simple/searx.min.js | <%= grunt.template.today("dd-mm-yyyy") %> | https://github.com/asciimoo/searx */\n',
output: {
comments: 'some'
},
ie8: false,
warnings: true,
compress: false,
mangle: true,
sourceMap: true
},
dist: {
files: {
'js/searx.min.js': ['<%= concat.dist.dest %>']
}
}
},
jshint: {
files: ['js/searx_src/*.js'],
files: ['js/searx_src/*.js', 'js/searx_header/*.js'],
options: {
reporterOutput: "",
proto: true,
@ -50,6 +23,36 @@ module.exports = function(grunt) {
}
}
},
concat: {
head_and_body: {
options: {
separator: ';'
},
files: {
'js/searx.head.js': ['js/searx_head/*.js'],
'js/searx.js': ['js/searx_src/*.js']
}
}
},
uglify: {
options: {
banner: '/*! simple/searx.min.js | <%= grunt.template.today("dd-mm-yyyy") %> | https://github.com/asciimoo/searx */\n',
output: {
comments: 'some'
},
ie8: false,
warnings: true,
compress: false,
mangle: true,
sourceMap: true
},
dist: {
files: {
'js/searx.head.min.js': ['js/searx.head.js'],
'js/searx.min.js': ['js/searx.js']
}
}
},
less: {
development: {
options: {

View file

@ -0,0 +1,40 @@
/**
* 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) 2019 by Alexandre Flament
*
*/
(function(w, d) {
'use strict';
// add data- properties
var script = d.currentScript || (function() {
var scripts = d.getElementsByTagName('script');
return scripts[scripts.length - 1];
})();
// try to detect touch screen
w.searx = {
touch: (("ontouchstart" in w) || w.DocumentTouch && document instanceof DocumentTouch) || false,
method: script.getAttribute('data-method'),
autocompleter: script.getAttribute('data-autocompleter') === 'true',
search_on_category_select: script.getAttribute('data-search-on-category-select') === 'true',
infinite_scroll: script.getAttribute('data-infinite-scroll') === 'true',
static_path: script.getAttribute('data-static-path'),
no_item_found: script.getAttribute('data-no-item-found')
}
// update the css
d.getElementsByTagName("html")[0].className = (w.searx.touch)?"js touch":"js";
})(window, document);

View file

@ -0,0 +1,4 @@
/*! simple/searx.min.js | 06-08-2019 | https://github.com/asciimoo/searx */
(function(t,e){"use strict";var a=e.currentScript||function(){var t=e.getElementsByTagName("script");return t[t.length-1]}();t.searx={touch:"ontouchstart"in t||t.DocumentTouch&&document instanceof DocumentTouch||false,method:a.getAttribute("data-method"),autocompleter:a.getAttribute("data-autocompleter")==="true",search_on_category_select:a.getAttribute("data-search-on-category-select")==="true",infinite_scroll:a.getAttribute("data-infinite-scroll")==="true",static_path:a.getAttribute("data-static-path"),no_item_found:a.getAttribute("data-no-item-found")};e.getElementsByTagName("html")[0].className=t.searx.touch?"js touch":"js"})(window,document);
//# sourceMappingURL=searx.head.min.js.map

View file

@ -0,0 +1 @@
{"version":3,"sources":["searx.head.js"],"names":["w","d","script","currentScript","scripts","getElementsByTagName","length","searx","touch","DocumentTouch","document","method","getAttribute","autocompleter","search_on_category_select","infinite_scroll","static_path","no_item_found","className","window"],"mappings":";;CAiBA,SAAUA,EAAGC,GACT,aAGA,IAAIC,EAASD,EAAEE,eAAkB,WAC7B,IAAIC,EAAUH,EAAEI,qBAAqB,UACrC,OAAOD,EAAQA,EAAQE,OAAS,GAFH,GAMjCN,EAAEO,MAAQ,CACNC,MAAS,iBAAkBR,GAAMA,EAAES,eAAiBC,oBAAoBD,eAAkB,MAC1FE,OAAQT,EAAOU,aAAa,eAC5BC,cAAeX,EAAOU,aAAa,wBAA0B,OAC7DE,0BAA2BZ,EAAOU,aAAa,oCAAsC,OACrFG,gBAAiBb,EAAOU,aAAa,0BAA4B,OACjEI,YAAad,EAAOU,aAAa,oBACjCK,cAAef,EAAOU,aAAa,uBAIvCX,EAAEI,qBAAqB,QAAQ,GAAGa,UAAalB,EAAEO,MAAW,MAAE,WAAW,MArB7E,CAsBGY,OAAQT","file":"searx.head.min.js"}

View file

@ -15,7 +15,7 @@
* (C) 2017 by Alexandre Flament, <alex@al-f.net>
*
*/
(function(w, d, searx) {
window.searx = (function(w, d) {
'use strict';
@ -45,7 +45,7 @@
}
}
searx = searx || {};
var searx = window.searx || {};
searx.on = function(obj, eventType, callback, useCapture) {
useCapture = useCapture || false;
@ -110,7 +110,7 @@
};
searx.loadStyle = function(src) {
var path = searx.staticPath + src,
var path = searx.static_path + src,
id = "style_" + src.replace('.', '_'),
s = d.getElementById(id);
if (s === null) {
@ -124,7 +124,7 @@
};
searx.loadScript = function(src, callback) {
var path = searx.staticPath + src,
var path = searx.static_path + src,
id = "script_" + src.replace('.', '_'),
s = d.getElementById(id);
if (s === null) {
@ -161,7 +161,7 @@
});
return searx;
})(window, document, window.searx);
})(window, document);
;(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.AutoComplete = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
/*
* @license MIT
@ -1529,7 +1529,7 @@ module.exports = AutoComplete;
if (searx.autocompleter) {
searx.autocomplete = AutoComplete.call(w, {
Url: "./autocompleter",
EmptyMessage: searx.noItemFound,
EmptyMessage: searx.no_item_found,
HttpMethod: searx.method,
MinChars: 4,
Delay: 300,

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,40 @@
/**
* 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) 2019 by Alexandre Flament
*
*/
(function(w, d) {
'use strict';
// add data- properties
var script = d.currentScript || (function() {
var scripts = d.getElementsByTagName('script');
return scripts[scripts.length - 1];
})();
// try to detect touch screen
w.searx = {
touch: (("ontouchstart" in w) || w.DocumentTouch && document instanceof DocumentTouch) || false,
method: script.getAttribute('data-method'),
autocompleter: script.getAttribute('data-autocompleter') === 'true',
search_on_category_select: script.getAttribute('data-search-on-category-select') === 'true',
infinite_scroll: script.getAttribute('data-infinite-scroll') === 'true',
static_path: script.getAttribute('data-static-path'),
no_item_found: script.getAttribute('data-no-item-found')
}
// update the css
d.getElementsByTagName("html")[0].className = (w.searx.touch)?"js touch":"js";
})(window, document);

View file

@ -15,7 +15,7 @@
* (C) 2017 by Alexandre Flament, <alex@al-f.net>
*
*/
(function(w, d, searx) {
window.searx = (function(w, d) {
'use strict';
@ -45,7 +45,7 @@
}
}
searx = searx || {};
var searx = window.searx || {};
searx.on = function(obj, eventType, callback, useCapture) {
useCapture = useCapture || false;
@ -110,7 +110,7 @@
};
searx.loadStyle = function(src) {
var path = searx.staticPath + src,
var path = searx.static_path + src,
id = "style_" + src.replace('.', '_'),
s = d.getElementById(id);
if (s === null) {
@ -124,7 +124,7 @@
};
searx.loadScript = function(src, callback) {
var path = searx.staticPath + src,
var path = searx.static_path + src,
id = "script_" + src.replace('.', '_'),
s = d.getElementById(id);
if (s === null) {
@ -161,4 +161,4 @@
});
return searx;
})(window, document, window.searx);
})(window, document);

View file

@ -73,7 +73,7 @@
if (searx.autocompleter) {
searx.autocomplete = AutoComplete.call(w, {
Url: "./autocompleter",
EmptyMessage: searx.noItemFound,
EmptyMessage: searx.no_item_found,
HttpMethod: searx.method,
MinChars: 4,
Delay: 300,

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,13 @@
<div class="result">
<table>
{% for key, value in result.items() %}
{% if key in ['engine', 'engines', 'template', 'score', 'category', 'positions'] %}
{% continue %}
{% endif %}
<tr>
<td><b>{{ key|upper }}</b>: {{ value|safe }}</td>
</tr>
{% endfor %}
</table>
<p class="engines">{{ result.engines|join(', ') }}</p>
</div>

View file

@ -4,7 +4,7 @@
{% endif %}
<h3 class="result_title"><a href="{{ result.url }}" {% if results_on_new_tab %}target="_blank" rel="noopener noreferrer"{% else %}rel="noreferrer"{% endif %}>{{ result.title|safe }}</a></h3>
{% if result.content %}<span class="content">{{ result.content|safe }}</span><br />{% endif %}
{% if result.seed %}<span class="stats">{{ _('Seeder') }} : {{ result.seed }}, {{ _('Leecher') }} : {{ result.leech }}</span><br />{% endif %}
{% if result.seed is defined %}<span class="stats">{{ _('Seeder') }} : {{ result.seed }}, {{ _('Leecher') }} : {{ result.leech }}</span><br />{% endif %}
<span>
{% if result.magnetlink %}<a href="{{ result.magnetlink }}" class="magnetlink">{{ _('magnet link') }}</a>{% endif %}
{% if result.torrentfile %}<a href="{{ result.torrentfile }}" class="torrentfile" {% if results_on_new_tab %}target="_blank" rel="noopener noreferrer"{% else %}rel="noreferrer"{% endif %}>{{ _('torrent file') }}</a>{% endif %}

View file

@ -0,0 +1,13 @@
<table class="result-table">
{% for key, value in result.items() %}
{% if key in ['engine', 'engines', 'template', 'score', 'category', 'positions'] %}
{% continue %}
{% endif %}
<tr>
<td><b>{{ key|upper }}</b>: {{ value|safe }}</td>
</tr>
{% endfor %}
<tr>
<td><b>ENGINES</b>: {{ result.engines|join(', ') }}</td>
</tr>
</table>

View file

@ -8,6 +8,6 @@
<p>
{% if result.magnetlink %}<a href="{{ result.magnetlink }}" class="magnetlink">{{ _('magnet link') }}</a>{% endif %}
{% if result.torrentfile %}<a href="{{ result.torrentfile }}" {% if results_on_new_tab %}target="_blank" rel="noopener noreferrer"{% else %}rel="noreferrer"{% endif %} class="torrentfile">{{ _('torrent file') }}</a>{% endif %} -
{% if result.seed %}<span class="stats">{{ _('Seeder') }} : {{ result.seed }}, {{ _('Leecher') }} : {{ result.leech }}</span>{% endif %}
{% if result.seed is defined %}<span class="stats">{{ _('Seeder') }} : {{ result.seed }}, {{ _('Leecher') }} : {{ result.leech }}</span>{% endif %}
</p>
</div>

View file

@ -1,16 +1,17 @@
<input type="checkbox" name="advanced_search" id="check-advanced" {% if advanced_search %} checked="checked"{% endif %}>
<label for="check-advanced">
<label for="check-advanced">{{- "" -}}
<span class="glyphicon glyphicon-cog"></span>
{{ _('Advanced settings') }}
{{- _('Advanced settings') -}}
</label>
<div id="advanced-search-container">
{% include 'oscar/categories.html' %}
<div class="row">
<div class="col-xs-6">
{% include 'oscar/time-range.html' %}
{%- include 'oscar/time-range.html' -%}
</div>
<div class="col-xs-6">
{% include 'oscar/languages.html' %}
{%- include 'oscar/languages.html' -%}
</div>
</div>
</div>

View file

@ -10,16 +10,17 @@
<meta name="referrer" content="no-referrer">
<meta name="viewport" content="width=device-width, initial-scale=1 , maximum-scale=1.0, user-scalable=1" />
{% block meta %}{% endblock %}
<title>{% block title %}{% endblock %}{{ instance_name }}</title>
<title>{% block title %}{% endblock %}{{ instance_name }}</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap.min.css') }}" type="text/css" />
{% if preferences.get_value('oscar-style') %}
<link rel="stylesheet" href="{{ url_for('static', filename='css/'+preferences.get_value('oscar-style')+'.min.css') }}" type="text/css" />
{% else %}
<link rel="stylesheet" href="{{ url_for('static', filename='css/logicodev.min.css') }}" type="text/css" />
{% endif %}
{% if preferences.get_value('oscar-style') -%}
{{' '}}<link rel="stylesheet" href="{{ url_for('static', filename='css/'+preferences.get_value('oscar-style')+'.min.css') }}" type="text/css" />
{%- else -%}
{{' '}}<link rel="stylesheet" href="{{ url_for('static', filename='css/logicodev.min.css') }}" type="text/css" />
{%- endif %}
<link rel="stylesheet" href="{{ url_for('static', filename='css/leaflet.min.css') }}" type="text/css" />
{% for css in styles %}
{%- for css in styles %}
<link rel="stylesheet" href="{{ url_for('static', filename=css) }}" type="text/css" />
{% endfor %}
@ -37,12 +38,6 @@
{% endblock %}
<link title="{{ instance_name }}" type="application/opensearchdescription+xml" rel="search" href="{{ url_for('opensearch') }}"/>
<script type="text/javascript">
searx = {};
searx.method = "{{ method or 'POST' }}";
searx.autocompleter = {% if autocomplete %}true{% else %}false{% endif %};
</script>
<noscript>
<style type="text/css">
.tab-content > .active_if_nojs, .active_if_nojs {display: block !important; visibility: visible !important;}
@ -54,6 +49,7 @@
</head>
<body>
{% include 'oscar/navbar.html' %}
<div class="container">
{% if errors %}
<div class="alert alert-danger fade in" role="alert">
@ -99,11 +95,14 @@
</div>
<script src="{{ url_for('static', filename='js/jquery-1.11.1.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/bootstrap.min.js') }}"></script>
{% if autocomplete %}<script src="{{ url_for('static', filename='js/typeahead.bundle.min.js') }}"></script>{% endif %}
{% if autocomplete %} <script src="{{ url_for('static', filename='js/typeahead.bundle.min.js') }}"></script>{% endif %}
<script src="{{ url_for('static', filename='js/require-2.1.15.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/searx.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/searx.min.js') }}"
data-method="{{ method or 'POST' }}"
data-autocompleter="{% if autocomplete %}true{% else %}false{% endif %}"></script>
{% for script in scripts %}
<script src="{{ url_for('static', filename=script) }}"></script>
{{""}}<script src="{{ url_for('static', filename=script) }}"></script>
{% endfor %}
<noscript>
<style>

View file

@ -1,13 +1,13 @@
<div id="categories">
{% if rtl %}
{% for category in categories | reverse %}
<input class="hidden" type="checkbox" id="checkbox_{{ category|replace(' ', '_') }}" name="category_{{ category }}" {% if category in selected_categories %}checked="checked"{% endif %} />
{%- if rtl -%}
{% for category in categories | reverse -%}
<input class="hidden" type="checkbox" id="checkbox_{{ category|replace(' ', '_') }}" name="category_{{ category }}" {% if category in selected_categories %}checked="checked"{% endif %} />{{- '' -}}
<label for="checkbox_{{ category|replace(' ', '_') }}">{{ _(category) }}</label>
{% endfor %}
{% else %}
{% for category in categories %}
<input class="hidden" type="checkbox" id="checkbox_{{ category|replace(' ', '_') }}" name="category_{{ category }}" {% if category in selected_categories %}checked="checked"{% endif %} />
{%- endfor %}
{%- else -%}
{% for category in categories -%}
<input class="hidden" type="checkbox" id="checkbox_{{ category|replace(' ', '_') }}" name="category_{{ category }}" {% if category in selected_categories %}checked="checked"{% endif %} />{{- '' -}}
<label for="checkbox_{{ category|replace(' ', '_') }}">{{ _(category) }}</label>
{% endfor %}
{% endif %}
{%- endfor %}
{%- endif -%}
</div>

View file

@ -1,34 +1,35 @@
{% from 'oscar/macros.html' import result_link with context %}
<div class="panel panel-default infobox">
<div class="panel-heading">
<h4 class="panel-title infobox_part"><bdi>{{ infobox.infobox }}</bdi></h4>
<div class="panel-heading">{{- "" -}}
<h4 class="panel-title infobox_part"><bdi>{{ infobox.infobox }}</bdi></h4>{{- "" -}}
</div>
<div class="panel-body">
{% if infobox.img_src %}<img class="img-responsive center-block infobox_part" src="{{ image_proxify(infobox.img_src) }}" alt="{{ infobox.infobox }}" />{% endif %}
{% if infobox.content %}<bdi><p class="infobox_part">{{ infobox.content }}</bdi></p>{% endif %}
{% if infobox.attributes %}
{% if infobox.content %}<bdi><p class="infobox_part">{{ infobox.content | safe }}</p></bdi>{% endif %}
{% if infobox.attributes -%}
<table class="table table-striped infobox_part">
{% for attribute in infobox.attributes %}
<tr>
{% for attribute in infobox.attributes -%}
<tr>{{- "" -}}
<td><bdi>{{ attribute.label }}</bdi></td>
{% if attribute.image %}
{%- if attribute.image -%}
<td><img class="img-responsive" src="{{ image_proxify(attribute.image.src) }}" alt="{{ attribute.image.alt }}" /></td>
{% else %}
{%- else -%}
<td><bdi>{{ attribute.value }}</bdi></td>
{% endif %}
{%- endif -%}
</tr>
{% endfor %}
{% endfor -%}
</table>
{% endif %}
{% if infobox.urls %}
<div class="infobox_part">
{% if infobox.urls -%}
<div class="infobox_part">{{- "\n" -}}
<bdi>
{% for url in infobox.urls %}
<p class="btn btn-default btn-xs">{{ result_link(url.url, url.title) }}</a></p>
{% endfor %}
</bdi>
{%- for url in infobox.urls -%}
<p class="btn btn-default btn-xs">{{ result_link(url.url, url.title) }}</p>
{% endfor -%}
</bdi>{{- "" -}}
</div>
{% endif %}
</div>

View file

@ -1,12 +1,8 @@
{% if preferences %}
<select class="custom-select form-control" name='language'>
{% else %}
<select class="time_range custom-select form-control" id='language' name='language'>
{% endif %}
<option value="all" {% if current_language == 'all' %}selected="selected"{% endif %}>{{ _('Default language') }}</option>
{% for lang_id,lang_name,country_name,english_name in language_codes | sort(attribute=1) %}
<option value="{{ lang_id }}" {% if lang_id == current_language %}selected="selected"{% endif %}>
{{ lang_name }} {% if country_name %}({{ country_name }}) {% endif %}- {{ lang_id }}
</option>
{% endfor %}
<select class="language custom-select form-control" id="language" name="language" accesskey="l">
<option value="all" {% if current_language == 'all' %}selected="selected"{% endif %}>{{ _('Default language') }}</option>
{%- for lang_id,lang_name,country_name,english_name in language_codes | sort(attribute=1) -%}
<option value="{{ lang_id }}" {% if lang_id == current_language %}selected="selected"{% endif %}>
{{- lang_name }} {% if country_name %}({{ country_name }}) {% endif %}- {{ lang_id -}}
</option>
{%- endfor -%}
</select>

View file

@ -14,7 +14,7 @@
<!-- Draw result header -->
{% macro result_header(result, favicons) -%}
<h4 class="result_header">{% if result.engine~".png" in favicons %}{{ draw_favicon(result.engine) }} {% endif %}{{ result_link(result.url, result.title|safe) }}</h4>
<h4 class="result_header">{% if result.engine~".png" in favicons %}{{ draw_favicon(result.engine) }} {% endif %}{% if result.url %}{{ result_link(result.url, result.title|safe) }}{% else %}{{ result.title|safe}}{% endif %}</h4>
{%- endmacro %}
<!-- Draw result sub header -->
@ -26,30 +26,38 @@
<!-- Draw result footer -->
{% macro result_footer(result) -%}
<div class="clearfix"></div>
<div class="clearfix"></div>{{- "" -}}
<div class="pull-right">
{% for engine in result.engines %}
<span class="label label-default">{{ engine }}</span>
{% endfor %}
<small>{{ result_link("https://web.archive.org/web/" + result.url, icon('link') + _('cached'), "text-info") }}</small>
{% if proxify %}
<small>{{ result_link(proxify(result.url), icon('sort') + _('proxied'), "text-info") }}</small>
{% endif %}
</div>
<div class="external-link">{{ result.pretty_url }}</div>
{%- for engine in result.engines -%}
<span class="label label-default">{{ engine }}</span>
{%- endfor -%}
{%- if result.url -%}
<small>{{ result_link("https://web.archive.org/web/" + result.url, icon('link') + _('cached'), "text-info") }}</small>
{%- endif -%}
{%- if proxify -%}
<small>{{ result_link(proxify(result.url), icon('sort') + _('proxied'), "text-info") }}</small>
{%- endif -%}
</div>
{%- if result.pretty_url -%}
<div class="external-link">{{ result.pretty_url }}</div>
{%- endif -%}
{%- endmacro %}
<!-- Draw result footer -->
{% macro result_footer_rtl(result) -%}
<div class="clearfix"></div>
{% for engine in result.engines %}
<div class="clearfix"></div>{{- "" -}}
{% for engine in result.engines -%}
<span class="label label-default">{{ engine }}</span>
{% endfor %}
{%- endfor %}
{%- if result.url -%}
<small>{{ result_link("https://web.archive.org/web/" + result.url, icon('link') + _('cached'), "text-info") }}</small>
{% if proxify %}
{%- endif -%}
{% if proxify -%}
<small>{{ result_link(proxify(result.url), icon('sort') + _('proxied'), "text-info") }}</small>
{% endif %}
{%- endif %}
{%- if result.pretty_url -%}
<div class="external-link">{{ result.pretty_url }}</div>
{%- endif %}
{%- endmacro %}
{% macro preferences_item_header(info, label, rtl) -%}

View file

@ -1,9 +1,9 @@
<div class="searx-navbar">
<span class="instance {% if rtl %}pull-right{% else %}pull-left{% endif%}">
<a href="{{ url_for('index') }}">{{ instance_name }}</a>
</span>
<span class="{% if rtl %}pull-left{% else %}pull-right{% endif %}">
<a href="{{ url_for('about') }}">{{ _('about') }}</a>
<a href="{{ url_for('preferences') }}">{{ _('preferences') }}</a>
</span>
<div class="searx-navbar">{{- "" -}}
<span class="instance {% if rtl %}pull-right{% else %}pull-left{% endif%}">{{- "" -}}
<a href="{{ url_for('index') }}">{{ instance_name }}</a>{{- "" -}}
</span>{{- "" -}}
<span class="{% if rtl %}pull-left{% else %}pull-right{% endif %}">{{- "" -}}
<a href="{{ url_for('about') }}">{{ _('about') }}</a>{{- "" -}}
<a href="{{ url_for('preferences') }}">{{ _('preferences') }}</a>{{- "" -}}
</span>{{- "" -}}
</div>

View file

@ -41,7 +41,7 @@
{% set language_label = _('Search language') %}
{% set language_info = _('What language do you prefer for search?') %}
{{ preferences_item_header(language_info, language_label, rtl) }}
{% include 'oscar/languages.html' %}
{% include 'oscar/languages.html' %}
{{ preferences_item_footer(language_info, language_label, rtl) }}
{% set locale_label = _('Interface language') %}
@ -156,26 +156,26 @@
<div class="container-fluid">
<fieldset>
<div class="table-responsive">
<table class="table table-hover table-condensed table-striped">
<tr>
<table class="table table-hover table-condensed table-striped">
<tr>
{% if not rtl %}
<th>{{ _("Allow") }}</th>
<th>{{ _("Engine name") }}</th>
<th>{{ _("Shortcut") }}</th>
<th>{{ _("Selected language") }}</th>
<th>{{ _("SafeSearch") }}</th>
<th>{{ _("Time range") }}</th>
<th>{{ _("Avg. time") }}</th>
<th>{{ _("Max time") }}</th>
<th>{{ _("Allow") }}</th>
<th>{{ _("Engine name") }}</th>
<th>{{ _("Shortcut") }}</th>
<th>{{ _("Selected language") }}</th>
<th>{{ _("SafeSearch") }}</th>
<th>{{ _("Time range") }}</th>
<th>{{ _("Avg. time") }}</th>
<th>{{ _("Max time") }}</th>
{% else %}
<th>{{ _("Max time") }}</th>
<th>{{ _("Avg. time") }}</th>
<th>{{ _("Time range") }}</th>
<th>{{ _("SafeSearch") }}</th>
<th>{{ _("Selected language") }}</th>
<th>{{ _("Shortcut") }}</th>
<th>{{ _("Engine name") }}</th>
<th>{{ _("Allow") }}</th>
<th>{{ _("Max time") }}</th>
<th>{{ _("Avg. time") }}</th>
<th>{{ _("Time range") }}</th>
<th>{{ _("SafeSearch") }}</th>
<th>{{ _("Selected language") }}</th>
<th>{{ _("Shortcut") }}</th>
<th>{{ _("Engine name") }}</th>
<th>{{ _("Allow") }}</th>
{% endif %}
</tr>
{% for search_engine in engines_by_category[categ] %}
@ -186,19 +186,19 @@
{{ checkbox_toggle('engine_' + search_engine.name|replace(' ', '_') + '__' + categ|replace(' ', '_'), (search_engine.name, categ) in disabled_engines) }}
</td>
<th>{{ search_engine.name }}</th>
<td class="name">{{ shortcuts[search_engine.name] }}</td>
<td>{{ support_toggle(stats[search_engine.name].supports_selected_language) }}</td>
<td>{{ support_toggle(search_engine.safesearch==True) }}</td>
<td>{{ support_toggle(search_engine.time_range_support==True) }}</td>
<td class="{{ 'danger' if stats[search_engine.name]['warn_time'] else '' }}">{{ 'N/A' if stats[search_engine.name].time==None else stats[search_engine.name].time }}</td>
<td class="{{ 'danger' if stats[search_engine.name]['warn_timeout'] else '' }}">{{ search_engine.timeout }}</td>
{% else %}
<td class="{{ 'danger' if stats[search_engine.name]['warn_timeout'] else '' }}">{{ search_engine.timeout }}</td>
<td class="{{ 'danger' if stats[search_engine.name]['warn_time'] else '' }}">{{ 'N/A' if stats[search_engine.name].time==None else stats[search_engine.name].time }}</td>
<td>{{ support_toggle(search_engine.time_range_support==True) }}</td>
<td>{{ support_toggle(search_engine.safesearch==True) }}</td>
<td>{{ support_toggle(stats[search_engine.name].supports_selected_language) }}</td>
<td>{{ shortcuts[search_engine.name] }}</td>
<td class="name">{{ shortcuts[search_engine.name] }}</td>
<td>{{ support_toggle(stats[search_engine.name].supports_selected_language) }}</td>
<td>{{ support_toggle(search_engine.safesearch==True) }}</td>
<td>{{ support_toggle(search_engine.time_range_support==True) }}</td>
<td class="{{ 'danger' if stats[search_engine.name]['warn_time'] else '' }}">{{ 'N/A' if stats[search_engine.name].time==None else stats[search_engine.name].time }}</td>
<td class="{{ 'danger' if stats[search_engine.name]['warn_timeout'] else '' }}">{{ search_engine.timeout }}</td>
{% else %}
<td class="{{ 'danger' if stats[search_engine.name]['warn_timeout'] else '' }}">{{ search_engine.timeout }}</td>
<td class="{{ 'danger' if stats[search_engine.name]['warn_time'] else '' }}">{{ 'N/A' if stats[search_engine.name].time==None else stats[search_engine.name].time }}</td>
<td>{{ support_toggle(search_engine.time_range_support==True) }}</td>
<td>{{ support_toggle(search_engine.safesearch==True) }}</td>
<td>{{ support_toggle(stats[search_engine.name].supports_selected_language) }}</td>
<td>{{ shortcuts[search_engine.name] }}</td>
<th>{{ search_engine.name }}</th>
<td class="onoff-checkbox">
{{ checkbox_toggle('engine_' + search_engine.name|replace(' ', '_') + '__' + categ|replace(' ', '_'), (search_engine.name, categ) in disabled_engines) }}
@ -207,7 +207,7 @@
</tr>
{% endif %}
{% endfor %}
</table>
</table>
</div>
</fieldset>
</div>

View file

@ -1,18 +1,18 @@
{% from 'oscar/macros.html' import result_header, result_sub_header, result_footer, result_footer_rtl, icon %}
{{ result_header(result, favicons) }}
{{ result_sub_header(result) }}
{% if result.content %}<p class="result-content">{{ result.content|safe }}</p>{% endif %}
{% if result.repository %}<p class="result-content">{{ icon('file') }} <a href="{{ result.repository }}" {% if results_on_new_tab %}target="_blank" rel="noopener noreferrer"{% else %}rel="noreferrer"{% endif %}>{{ result.repository }}</a></p>{% endif %}
<div dir="ltr">
{{ result.codelines|code_highlighter(result.code_language)|safe }}
</div>
{% if rtl %}
{{ result_footer_rtl(result) }}
{% else %}
{{ result_footer(result) }}
{% endif %}
{% from 'oscar/macros.html' import result_header, result_sub_header, result_footer, result_footer_rtl, icon %}
{{ result_header(result, favicons) }}
{{ result_sub_header(result) }}
{% if result.content %}<p class="result-content">{{ result.content|safe }}</p>{% endif %}
{% if result.repository %}<p class="result-content">{{ icon('file') }} <a href="{{ result.repository }}" {% if results_on_new_tab %}target="_blank" rel="noopener noreferrer"{% else %}rel="noreferrer"{% endif %}>{{ result.repository }}</a></p>{% endif %}
<div dir="ltr">
{{ result.codelines|code_highlighter(result.code_language)|safe }}
</div>
{% if rtl %}
{{ result_footer_rtl(result) }}
{% else %}
{{ result_footer(result) }}
{% endif %}

Some files were not shown because too many files have changed in this diff Show more