Merge pull request #1 from asciimoo/master

-
This commit is contained in:
Apply55gx 2017-10-25 10:44:28 +02:00 committed by GitHub
commit d800e3fcfa
49 changed files with 754 additions and 1473 deletions

31
.codecov.yml Normal file
View File

@ -0,0 +1,31 @@
comment: false
coverage:
status:
project:
default:
# basic
target: auto
threshold: null
base: auto
# advanced
branches: null
if_no_uploads: error
if_not_found: success
if_ci_failed: error
only_pulls: false
flags: null
paths: null
patch:
default:
# basic
target: auto
threshold: null
base: auto
# advanced
branches: null
if_no_uploads: error
if_not_found: success
if_ci_failed: error
only_pulls: false
flags: null
paths: null

View File

@ -13,21 +13,21 @@ python:
before_install:
- "export DISPLAY=:99.0"
- "sh -e /etc/init.d/xvfb start"
- npm install less less-plugin-clean-css grunt-cli
- npm install less@2.7 less-plugin-clean-css grunt-cli
- export PATH=`pwd`/node_modules/.bin:$PATH
- ./manage.sh install_geckodriver ~/drivers
- export PATH=~/drivers:$PATH
install:
- ./manage.sh npm_packages
- ./manage.sh update_dev_packages
- pip install coveralls
- pip install codecov
script:
- ./manage.sh styles
- ./manage.sh grunt_build
- ./manage.sh tests
after_success:
- ./manage.sh py_test_coverage
- coveralls
- codecov
notifications:
irc:
channels:

View File

@ -9,7 +9,8 @@ instances <https://github.com/asciimoo/searx/wiki/Searx-instances>`__.
See the `documentation <https://asciimoo.github.io/searx>`__ and the `wiki <https://github.com/asciimoo/searx/wiki>`__ for more information.
|Flattr searx|
|OpenCollective searx backers|
|OpenCollective searx sponsors|
Installation
~~~~~~~~~~~~
@ -41,5 +42,10 @@ More about searx
- `twitter <https://twitter.com/Searx_engine>`__
- IRC: #searx @ freenode
.. |Flattr searx| image:: http://api.flattr.com/button/flattr-badge-large.png
:target: https://flattr.com/submit/auto?user_id=asciimoo&url=https://github.com/asciimoo/searx&title=searx&language=&tags=github&category=software
.. |OpenCollective searx backers| image:: https://opencollective.com/searx/backers/badge.svg
:target: https://opencollective.com/searx#backer
.. |OpenCollective searx sponsors| image:: https://opencollective.com/searx/sponsors/badge.svg
:target: https://opencollective.com/searx#sponsor

View File

@ -1,11 +1,11 @@
#!/bin/sh
BASE_DIR=$(dirname "`readlink -f "$0"`")
PYTHONPATH=$BASE_DIR
BASE_DIR="$(dirname -- "`readlink -f -- "$0"`")"
PYTHONPATH="$BASE_DIR"
SEARX_DIR="$BASE_DIR/searx"
ACTION=$1
ACTION="$1"
cd "$BASE_DIR"
cd -- "$BASE_DIR"
update_packages() {
pip install --upgrade pip
@ -22,40 +22,40 @@ install_geckodriver() {
echo '[!] Checking geckodriver'
# TODO : check the current geckodriver version
set -e
geckodriver -V 2>1 > /dev/null || NOTFOUND=1
geckodriver -V > /dev/null 2>&1 || NOTFOUND=1
set +e
if [ -z $NOTFOUND ]; then
return
if [ -z "$NOTFOUND" ]; then
return
fi
GECKODRIVER_VERSION="v0.18.0"
PLATFORM=`python -c "import six; import platform; six.print_(platform.system().lower(), platform.architecture()[0])"`
case $PLATFORM in
"linux 32bit" | "linux2 32bit") ARCH="linux32";;
"linux 64bit" | "linux2 64bit") ARCH="linux64";;
"windows 32 bit") ARCH="win32";;
"windows 64 bit") ARCH="win64";;
"mac 64bit") ARCH="macos";;
PLATFORM="`python -c "import six; import platform; six.print_(platform.system().lower(), platform.architecture()[0])"`"
case "$PLATFORM" in
"linux 32bit" | "linux2 32bit") ARCH="linux32";;
"linux 64bit" | "linux2 64bit") ARCH="linux64";;
"windows 32 bit") ARCH="win32";;
"windows 64 bit") ARCH="win64";;
"mac 64bit") ARCH="macos";;
esac
GECKODRIVER_URL="https://github.com/mozilla/geckodriver/releases/download/$GECKODRIVER_VERSION/geckodriver-$GECKODRIVER_VERSION-$ARCH.tar.gz";
if [ -z "$1" ]; then
if [ -z "$VIRTUAL_ENV" ]; then
echo "geckodriver can't be installed because VIRTUAL_ENV is not set, you should download it from\n $GECKODRIVER_URL"
exit
else
GECKODRIVER_DIR="$VIRTUAL_ENV/bin"
fi
if [ -z "$VIRTUAL_ENV" ]; then
echo "geckodriver can't be installed because VIRTUAL_ENV is not set, you should download it from\n $GECKODRIVER_URL"
exit
else
GECKODRIVER_DIR="$VIRTUAL_ENV/bin"
fi
else
GECKODRIVER_DIR="$1"
mkdir -p "$GECKODRIVER_DIR"
GECKODRIVER_DIR="$1"
mkdir -p -- "$GECKODRIVER_DIR"
fi
echo "Installing $GECKODRIVER_DIR/geckodriver from\n $GECKODRIVER_URL"
FILE=`mktemp`
wget "$GECKODRIVER_URL" -qO $FILE && tar xz -C "$GECKODRIVER_DIR" -f $FILE geckodriver
rm $FILE
chmod 777 "$GECKODRIVER_DIR/geckodriver"
FILE="`mktemp`"
wget -qO "$FILE" -- "$GECKODRIVER_URL" && tar xz -C "$GECKODRIVER_DIR" -f "$FILE" geckodriver
rm -- "$FILE"
chmod 777 -- "$GECKODRIVER_DIR/geckodriver"
}
pep8_check() {
@ -73,14 +73,14 @@ unit_tests() {
py_test_coverage() {
echo '[!] Running python test coverage'
PYTHONPATH=`pwd` python -m nose2 -C --coverage "$SEARX_DIR" -s "$BASE_DIR/tests/unit"
coverage report
coverage html
PYTHONPATH="`pwd`" python -m nose2 -C --log-capture --with-coverage --coverage "$SEARX_DIR" -s "$BASE_DIR/tests/unit" \
&& coverage report \
&& coverage html
}
robot_tests() {
echo '[!] Running robot tests'
PYTHONPATH=`pwd` python "$SEARX_DIR/testing.py" robot
PYTHONPATH="`pwd`" python "$SEARX_DIR/testing.py" robot
}
tests() {
@ -113,18 +113,18 @@ styles() {
npm_packages() {
echo '[!] install NPM packages for oscar theme'
cd $BASE_DIR/searx/static/themes/oscar
cd -- "$BASE_DIR/searx/static/themes/oscar"
npm install
echo '[!] install NPM packages for simple theme'
cd $BASE_DIR/searx/static/themes/simple
echo '[!] install NPM packages for simple theme'
cd -- "$BASE_DIR/searx/static/themes/simple"
npm install
}
grunt_build() {
echo '[!] Grunt build : oscar theme'
grunt --gruntfile "$SEARX_DIR/static/themes/oscar/gruntfile.js"
echo '[!] Grunt build : simple theme'
echo '[!] Grunt build : simple theme'
grunt --gruntfile "$SEARX_DIR/static/themes/simple/gruntfile.js"
}
@ -133,7 +133,7 @@ locales() {
}
help() {
[ -z "$1" ] || printf "Error: $1\n"
[ -z "$1" ] || printf 'Error: %s\n' "$1"
echo "Searx manage.sh help
Commands
@ -156,4 +156,4 @@ Commands
[ "$(command -V "$ACTION" | grep ' function$')" = "" ] \
&& help "action not found" \
|| $ACTION "$2"
|| "$ACTION" "$2"

View File

@ -1,6 +1,7 @@
babel==2.3.4
mock==2.0.0
nose2[coverage-plugin]
cov-core==1.15.0
pep8==1.7.0
plone.testing==5.0.0
splinter==0.7.5

View File

@ -7,4 +7,4 @@ pygments==2.1.3
pyopenssl==17.2.0
python-dateutil==2.6.1
pyyaml==3.12
requests[socks]==2.14.2
requests[socks]==2.18.4

File diff suppressed because one or more lines are too long

View File

@ -18,7 +18,6 @@
from lxml import html
from json import loads
import re
from searx.engines.bing import _fetch_supported_languages, supported_languages_url
from searx.url_utils import urlencode
# engine dependent config
@ -26,6 +25,8 @@ categories = ['images']
paging = True
safesearch = True
time_range_support = True
language_support = True
supported_languages_url = 'https://www.bing.com/account/general'
# search-url
base_url = 'https://www.bing.com/'
@ -45,23 +46,41 @@ safesearch_types = {2: 'STRICT',
_quote_keys_regex = re.compile('({|,)([a-z][a-z0-9]*):(")', re.I | re.U)
# get supported region code
def get_region_code(lang, lang_list=None):
region = None
if lang in (lang_list or supported_languages):
region = lang
elif lang.startswith('no'):
region = 'nb-NO'
else:
# try to get a supported country code with language
lang = lang.split('-')[0]
for lc in (lang_list or supported_languages):
if lang == lc.split('-')[0]:
region = lc
break
if region:
return region.lower()
else:
return 'en-us'
# do search-request
def request(query, params):
offset = (params['pageno'] - 1) * 10 + 1
# required for cookie
if params['language'] == 'all':
language = 'en-US'
else:
language = params['language']
search_path = search_string.format(
query=urlencode({'q': query}),
offset=offset)
language = get_region_code(params['language'])
params['cookies']['SRCHHPGUSR'] = \
'NEWWND=0&NRSLT=-1&SRCHLANG=' + language.split('-')[0] +\
'&ADLT=' + safesearch_types.get(params['safesearch'], 'DEMOTE')
'ADLT=' + safesearch_types.get(params['safesearch'], 'DEMOTE')
params['cookies']['_EDGE_S'] = 'mkt=' + language +\
'&ui=' + language + '&F=1'
params['url'] = base_url + search_path
if params['time_range'] in time_range_dict:
@ -106,3 +125,22 @@ def response(resp):
# return results
return results
# get supported languages from their site
def _fetch_supported_languages(resp):
supported_languages = []
dom = html.fromstring(resp.text)
regions_xpath = '//div[@id="region-section-content"]' \
+ '//ul[@class="b_vList"]/li/a/@href'
regions = dom.xpath(regions_xpath)
for region in regions:
code = re.search('setmkt=[^\&]+', region).group()[7:]
if code == 'nb-NO':
code = 'no-NO'
supported_languages.append(code)
return supported_languages

View File

@ -12,6 +12,7 @@
from json import loads
from lxml import html
from searx.engines.bing_images import _fetch_supported_languages, supported_languages_url, get_region_code
from searx.engines.xpath import extract_text
from searx.url_utils import urlencode
@ -21,6 +22,7 @@ paging = True
safesearch = True
time_range_support = True
number_of_results = 10
language_support = True
search_url = 'https://www.bing.com/videos/asyncv2?{query}&async=content&'\
'first={offset}&count={number_of_results}&CW=1366&CH=25&FORM=R5VR5'
@ -45,7 +47,8 @@ def request(query, params):
'ADLT=' + safesearch_types.get(params['safesearch'], 'DEMOTE')
# language cookie
params['cookies']['_EDGE_S'] = 'mkt=' + params['language'].lower() + '&F=1'
region = get_region_code(params['language'], lang_list=supported_languages)
params['cookies']['_EDGE_S'] = 'mkt=' + region + '&F=1'
# query and paging
params['url'] = search_url.format(query=urlencode({'q': query}),

View File

@ -1,70 +0,0 @@
"""
Blekko (Images)
@website https://blekko.com
@provide-api yes (inofficial)
@using-api yes
@results JSON
@stable yes
@parse url, title, img_src
"""
from json import loads
from searx.url_utils import urlencode
# engine dependent config
categories = ['images']
paging = True
safesearch = True
# search-url
base_url = 'https://blekko.com'
search_url = '/api/images?{query}&c={c}'
# safesearch definitions
safesearch_types = {2: '1',
1: '',
0: '0'}
# do search-request
def request(query, params):
c = (params['pageno'] - 1) * 48
params['url'] = base_url +\
search_url.format(query=urlencode({'q': query}),
c=c)
if params['pageno'] != 1:
params['url'] += '&page={pageno}'.format(pageno=(params['pageno'] - 1))
# let Blekko know we wan't have profiling
params['cookies']['tag_lesslogging'] = '1'
# parse safesearch argument
params['cookies']['safesearch'] = safesearch_types.get(params['safesearch'], '')
return params
# get response from search-request
def response(resp):
results = []
search_results = loads(resp.text)
# return empty array if there are no results
if not search_results:
return []
for result in search_results:
# append result
results.append({'url': result['page_url'],
'title': result['title'],
'content': '',
'img_src': result['url'],
'template': 'images.html'})
# return results
return results

View File

@ -10,6 +10,8 @@
@parse url, title, content, publishedDate, thumbnail
"""
import random
import string
from dateutil import parser
from json import loads
from lxml import html
@ -30,12 +32,17 @@ title_xpath = './/h2//a//text()'
content_xpath = './/p//text()'
pubdate_xpath = './/time'
digg_cookie_chars = string.ascii_uppercase + string.ascii_lowercase +\
string.digits + "+_"
# do search-request
def request(query, params):
offset = (params['pageno'] - 1) * 10
params['url'] = search_url.format(position=offset,
query=quote_plus(query))
params['cookies']['frontend.auid'] = ''.join(random.choice(
digg_cookie_chars) for _ in range(22))
return params

View File

@ -134,4 +134,4 @@ def _fetch_supported_languages(resp):
regions_json = loads(response_page)
supported_languages = map((lambda x: x[3:] + '-' + x[:2].upper()), regions_json.keys())
return supported_languages
return list(supported_languages)

View File

@ -4,7 +4,7 @@
@website http://www.faroo.com
@provide-api yes (http://www.faroo.com/hp/api/api.html), require API-key
@using-api yes
@using-api no
@results JSON
@stable yes
@parse url, title, content, publishedDate, img_src
@ -20,18 +20,16 @@ categories = ['general', 'news']
paging = True
language_support = True
number_of_results = 10
api_key = None
# search-url
url = 'http://www.faroo.com/'
search_url = url + 'api?{query}'\
'&start={offset}'\
'&length={number_of_results}'\
'&l={language}'\
'&src={categorie}'\
'&i=false'\
'&f=json'\
'&key={api_key}' # noqa
search_url = url + 'instant.json?{query}'\
'&start={offset}'\
'&length={number_of_results}'\
'&l={language}'\
'&src={categorie}'\
'&i=false'\
'&c=false'
search_category = {'general': 'web',
'news': 'news'}
@ -57,21 +55,15 @@ def request(query, params):
number_of_results=number_of_results,
query=urlencode({'q': query}),
language=language,
categorie=categorie,
api_key=api_key)
categorie=categorie)
# using searx User-Agent
params['headers']['User-Agent'] = searx_useragent()
params['headers']['Referer'] = url
return params
# get response from search-request
def response(resp):
# HTTP-Code 401: api-key is not valide
if resp.status_code == 401:
raise Exception("API key is not valide")
# HTTP-Code 429: rate limit exceeded
if resp.status_code == 429:
raise Exception("rate limit has been exceeded!")
@ -86,31 +78,19 @@ def response(resp):
# parse results
for result in search_res['results']:
publishedDate = None
result_json = {'url': result['url'], 'title': result['title'],
'content': result['kwic']}
if result['news']:
# timestamp (milliseconds since 1970)
publishedDate = datetime.datetime.fromtimestamp(result['date'] / 1000.0) # noqa
# append news result
results.append({'url': result['url'],
'title': result['title'],
'publishedDate': publishedDate,
'content': result['kwic']})
else:
# append general result
# TODO, publishedDate correct?
results.append({'url': result['url'],
'title': result['title'],
'content': result['kwic']})
result_json['publishedDate'] = \
datetime.datetime.fromtimestamp(result['date'] / 1000.0)
# append image result if image url is set
# TODO, show results with an image like in faroo
if result['iurl']:
results.append({'template': 'images.html',
'url': result['url'],
'title': result['title'],
'content': result['kwic'],
'img_src': result['iurl']})
result_json['template'] = 'videos.html'
result_json['thumbnail'] = result['iurl']
results.append(result_json)
# return results
return results

View File

@ -1,62 +0,0 @@
"""
General Files (Files)
@website http://www.general-files.org
@provide-api no (nothing found)
@using-api no (because nothing found)
@results HTML (using search portal)
@stable no (HTML can change)
@parse url, title, content
@todo detect torrents?
"""
from lxml import html
# engine dependent config
categories = ['files']
paging = True
# search-url
base_url = 'http://www.general-file.com'
search_url = base_url + '/files-{letter}/{query}/{pageno}'
# specific xpath variables
result_xpath = '//table[@class="block-file"]'
title_xpath = './/h2/a//text()'
url_xpath = './/h2/a/@href'
content_xpath = './/p//text()'
# do search-request
def request(query, params):
params['url'] = search_url.format(query=query,
letter=query[0],
pageno=params['pageno'])
return params
# get response from search-request
def response(resp):
results = []
dom = html.fromstring(resp.text)
# parse results
for result in dom.xpath(result_xpath):
url = result.xpath(url_xpath)[0]
# skip fast download links
if not url.startswith('/'):
continue
# append result
results.append({'url': base_url + url,
'title': ''.join(result.xpath(title_xpath)),
'content': ''.join(result.xpath(content_xpath))})
# return results
return results

View File

@ -10,6 +10,7 @@
@parse url, title, content
"""
import random
from json import loads
from time import time
from lxml.html import fromstring
@ -32,7 +33,8 @@ search_string = 'search?{query}'\
'&qh=0'\
'&qlang={lang}'\
'&ff={safesearch}'\
'&rxikd={rxikd}' # random number - 9 digits
'&rxieu={rxieu}'\
'&rand={rxikd}' # current unix timestamp
# specific xpath variables
results_xpath = '//response//result'
@ -59,10 +61,12 @@ def request(query, params):
else:
safesearch = 0
# rxieu is some kind of hash from the search query, but accepts random atm
search_path = search_string.format(query=urlencode({'q': query}),
offset=offset,
number_of_results=number_of_results,
rxikd=str(time())[:9],
rxikd=int(time() * 1000),
rxieu=random.randint(1000000000, 9999999999),
lang=language,
safesearch=safesearch)

View File

@ -67,8 +67,8 @@ def response(resp):
for result in dom.xpath('//div[@class="g"]|//div[@class="g _cy"]'):
try:
r = {
'url': result.xpath('.//div[@class="_cnc"]//a/@href')[0],
'title': ''.join(result.xpath('.//div[@class="_cnc"]//h3//text()')),
'url': result.xpath('.//a[@class="l _PMs"]')[0].attrib.get("href"),
'title': ''.join(result.xpath('.//a[@class="l _PMs"]//text()')),
'content': ''.join(result.xpath('.//div[@class="st"]//text()')),
}
except:

View File

@ -1,7 +1,7 @@
"""
Nyaa.se (Anime Bittorrent tracker)
Nyaa.si (Anime Bittorrent tracker)
@website http://www.nyaa.se/
@website http://www.nyaa.si/
@provide-api no
@using-api no
@results HTML
@ -12,50 +12,25 @@
from lxml import html
from searx.engines.xpath import extract_text
from searx.url_utils import urlencode
from searx.utils import get_torrent_size, int_or_zero
# engine dependent config
categories = ['files', 'images', 'videos', 'music']
paging = True
# search-url
base_url = 'http://www.nyaa.se/'
base_url = 'http://www.nyaa.si/'
search_url = base_url + '?page=search&{query}&offset={offset}'
# xpath queries
xpath_results = '//table[@class="tlist"]//tr[contains(@class, "tlistrow")]'
xpath_category = './/td[@class="tlisticon"]/a'
xpath_title = './/td[@class="tlistname"]/a'
xpath_torrent_file = './/td[@class="tlistdownload"]/a'
xpath_filesize = './/td[@class="tlistsize"]/text()'
xpath_seeds = './/td[@class="tlistsn"]/text()'
xpath_leeches = './/td[@class="tlistln"]/text()'
xpath_downloads = './/td[@class="tlistdn"]/text()'
# convert a variable to integer or return 0 if it's not a number
def int_or_zero(num):
if isinstance(num, list):
if len(num) < 1:
return 0
num = num[0]
if num.isdigit():
return int(num)
return 0
# get multiplier to convert torrent size to bytes
def get_filesize_mul(suffix):
return {
'KB': 1024,
'MB': 1024 ** 2,
'GB': 1024 ** 3,
'TB': 1024 ** 4,
'KIB': 1024,
'MIB': 1024 ** 2,
'GIB': 1024 ** 3,
'TIB': 1024 ** 4
}[str(suffix).upper()]
xpath_results = '//table[contains(@class, "torrent-list")]//tr[not(th)]'
xpath_category = './/td[1]/a[1]'
xpath_title = './/td[2]/a[last()]'
xpath_torrent_links = './/td[3]/a'
xpath_filesize = './/td[4]/text()'
xpath_seeds = './/td[6]/text()'
xpath_leeches = './/td[7]/text()'
xpath_downloads = './/td[8]/text()'
# do search-request
@ -72,25 +47,32 @@ def response(resp):
dom = html.fromstring(resp.text)
for result in dom.xpath(xpath_results):
# defaults
filesize = 0
magnet_link = ""
torrent_link = ""
# category in which our torrent belongs
category = result.xpath(xpath_category)[0].attrib.get('title')
try:
category = result.xpath(xpath_category)[0].attrib.get('title')
except:
pass
# torrent title
page_a = result.xpath(xpath_title)[0]
title = extract_text(page_a)
# link to the page
href = page_a.attrib.get('href')
href = base_url + page_a.attrib.get('href')
# link to the torrent file
torrent_link = result.xpath(xpath_torrent_file)[0].attrib.get('href')
# torrent size
try:
file_size, suffix = result.xpath(xpath_filesize)[0].split(' ')
file_size = int(float(file_size) * get_filesize_mul(suffix))
except:
file_size = None
for link in result.xpath(xpath_torrent_links):
url = link.attrib.get('href')
if 'magnet' in url:
# link to the magnet
magnet_link = url
else:
# link to the torrent file
torrent_link = url
# seed count
seed = int_or_zero(result.xpath(xpath_seeds))
@ -101,6 +83,14 @@ def response(resp):
# torrent downloads count
downloads = int_or_zero(result.xpath(xpath_downloads))
# let's try to calculate the torrent size
try:
filesize_info = result.xpath(xpath_filesize)[0]
filesize, filesize_multiplier = filesize_info.split()
filesize = get_torrent_size(filesize, filesize_multiplier)
except:
pass
# content string contains all information not included into template
content = 'Category: "{category}". Downloaded {downloads} times.'
content = content.format(category=category, downloads=downloads)
@ -110,8 +100,9 @@ def response(resp):
'content': content,
'seed': seed,
'leech': leech,
'filesize': file_size,
'filesize': filesize,
'torrentfile': torrent_link,
'magnetlink': magnet_link,
'template': 'torrent.html'})
return results

View File

@ -118,7 +118,7 @@ def _fetch_supported_languages(resp):
dom = fromstring(resp.text)
options = dom.xpath('//div[@id="regions-popup"]//ul/li/a')
for option in options:
code = option.xpath('./@data-val')[0]
code = option.xpath('./@data-search-language')[0]
if code.startswith('nb-'):
code = code.replace('nb', 'no', 1)
supported_languages.append(code)

View File

@ -14,8 +14,8 @@ import re
from lxml import html
from searx.engines.xpath import extract_text
from datetime import datetime
from searx.engines.nyaa import int_or_zero, get_filesize_mul
from searx.url_utils import urlencode
from searx.utils import get_torrent_size, int_or_zero
# engine dependent config
categories = ['files', 'videos', 'music']
@ -76,8 +76,7 @@ def response(resp):
try:
# ('1.228', 'GB')
groups = size_re.match(item).groups()
multiplier = get_filesize_mul(groups[1])
params['filesize'] = int(multiplier * float(groups[0]))
params['filesize'] = get_torrent_size(groups[0], groups[1])
except:
pass
elif item.startswith('Date:'):

View File

@ -1,7 +1,7 @@
"""
Torrentz.eu (BitTorrent meta-search engine)
Torrentz2.eu (BitTorrent meta-search engine)
@website https://torrentz.eu/
@website https://torrentz2.eu/
@provide-api no
@using-api no
@ -14,24 +14,24 @@
import re
from lxml import html
from datetime import datetime
from searx.engines.nyaa import int_or_zero, get_filesize_mul
from searx.engines.xpath import extract_text
from searx.url_utils import urlencode
from searx.utils import get_torrent_size
# engine dependent config
categories = ['files', 'videos', 'music']
paging = True
# search-url
# https://torrentz.eu/search?f=EXAMPLE&p=6
base_url = 'https://torrentz.eu/'
# https://torrentz2.eu/search?f=EXAMPLE&p=6
base_url = 'https://torrentz2.eu/'
search_url = base_url + 'search?{query}'
# do search-request
def request(query, params):
page = params['pageno'] - 1
query = urlencode({'q': query, 'p': page})
query = urlencode({'f': query, 'p': page})
params['url'] = search_url.format(query=query)
return params
@ -54,22 +54,29 @@ def response(resp):
# extract url and remove a slash in the beginning
link = links[0].attrib.get('href').lstrip('/')
seed = result.xpath('./dd/span[@class="u"]/text()')[0].replace(',', '')
leech = result.xpath('./dd/span[@class="d"]/text()')[0].replace(',', '')
seed = 0
leech = 0
try:
seed = int(result.xpath('./dd/span[4]/text()')[0].replace(',', ''))
leech = int(result.xpath('./dd/span[5]/text()')[0].replace(',', ''))
except:
pass
params = {
'url': base_url + link,
'title': title,
'seed': int_or_zero(seed),
'leech': int_or_zero(leech),
'seed': seed,
'leech': leech,
'template': 'torrent.html'
}
# let's try to calculate the torrent size
try:
size_str = result.xpath('./dd/span[@class="s"]/text()')[0]
size, suffix = size_str.split()
params['filesize'] = int(size) * get_filesize_mul(suffix)
filesize_info = result.xpath('./dd/span[3]/text()')[0]
filesize, filesize_multiplier = filesize_info.split()
filesize = get_torrent_size(filesize, filesize_multiplier)
params['filesize'] = filesize
except:
pass
@ -80,9 +87,8 @@ def response(resp):
# extract and convert creation date
try:
date_str = result.xpath('./dd/span[@class="a"]/span')[0].attrib.get('title')
# Fri, 25 Mar 2016 16:29:01
date = datetime.strptime(date_str, '%a, %d %b %Y %H:%M:%S')
date_ts = result.xpath('./dd/span[2]')[0].attrib.get('title')
date = datetime.fromtimestamp(float(date_ts))
params['publishedDate'] = date
except:
pass

View File

@ -5,6 +5,11 @@
language_codes = (
(u"ar-SA", u"العربية", u"", u"Arabic"),
(u"bg-BG", u"Български", u"", u"Bulgarian"),
(u"ca", u"Català", u"", u"Catalan"),
(u"ca-AD", u"Català", u"Andorra", u"Catalan"),
(u"ca-CT", u"Català", u"", u"Catalan"),
(u"ca-ES", u"Català", u"Espanya", u"Catalan"),
(u"ca-FR", u"Català", u"França", u"Catalan"),
(u"cs-CZ", u"Čeština", u"", u"Czech"),
(u"da-DK", u"Dansk", u"", u"Danish"),
(u"de", u"Deutsch", u"", u"German"),
@ -15,9 +20,7 @@ language_codes = (
(u"en", u"English", u"", u"English"),
(u"en-AU", u"English", u"Australia", u"English"),
(u"en-CA", u"English", u"Canada", u"English"),
(u"en-CY", u"English", u"Cyprus", u"English"),
(u"en-GB", u"English", u"United Kingdom", u"English"),
(u"en-GD", u"English", u"Grenada", u"English"),
(u"en-ID", u"English", u"Indonesia", u"English"),
(u"en-IE", u"English", u"Ireland", u"English"),
(u"en-IN", u"English", u"India", u"English"),
@ -28,6 +31,7 @@ language_codes = (
(u"en-US", u"English", u"United States", u"English"),
(u"en-ZA", u"English", u"South Africa", u"English"),
(u"es", u"Español", u"", u"Spanish"),
(u"es-AD", u"Español", u"Andorra", u"Spanish"),
(u"es-AR", u"Español", u"Argentina", u"Spanish"),
(u"es-CL", u"Español", u"Chile", u"Spanish"),
(u"es-CO", u"Español", u"Colombia", u"Spanish"),
@ -38,38 +42,32 @@ language_codes = (
(u"et-EE", u"Eesti", u"", u"Estonian"),
(u"fi-FI", u"Suomi", u"", u"Finnish"),
(u"fr", u"Français", u"", u"French"),
(u"fr-AD", u"Français", u"Andorre", u"French"),
(u"fr-BE", u"Français", u"Belgique", u"French"),
(u"fr-CA", u"Français", u"Canada", u"French"),
(u"fr-CH", u"Français", u"Suisse", u"French"),
(u"fr-FR", u"Français", u"France", u"French"),
(u"he-IL", u"עברית", u"", u"Hebrew"),
(u"hr-HR", u"Hrvatski", u"", u"Croatian"),
(u"hu-HU", u"Magyar", u"", u"Hungarian"),
(u"id-ID", u"Bahasa Indonesia", u"", u"Indonesian"),
(u"it", u"Italiano", u"", u"Italian"),
(u"it-CH", u"Italiano", u"Svizzera", u"Italian"),
(u"it-IT", u"Italiano", u"Italia", u"Italian"),
(u"ja-JP", u"日本語", u"", u"Japanese"),
(u"ko-KR", u"한국어", u"", u"Korean"),
(u"lt-LT", u"Lietuvių", u"", u"Lithuanian"),
(u"lv-LV", u"Latviešu", u"", u"Latvian"),
(u"ms-MY", u"Bahasa Melayu", u"", u"Malay"),
(u"nl", u"Nederlands", u"", u"Dutch"),
(u"nl-BE", u"Nederlands", u"België", u"Dutch"),
(u"nl-NL", u"Nederlands", u"Nederland", u"Dutch"),
(u"no-NO", u"Norsk", u"", u"Norwegian"),
(u"pl-PL", u"Polski", u"", u"Polish"),
(u"pt", u"Português", u"", u"Portuguese"),
(u"pt-AD", u"Português", u"Andorra", u"Portuguese"),
(u"pt-BR", u"Português", u"Brasil", u"Portuguese"),
(u"pt-PT", u"Português", u"Portugal", u"Portuguese"),
(u"ro-RO", u"Română", u"", u"Romanian"),
(u"ru-RU", u"Русский", u"", u"Russian"),
(u"sk-SK", u"Slovenčina", u"", u"Slovak"),
(u"sl", u"Slovenščina", u"", u"Slovenian"),
(u"sv-SE", u"Svenska", u"", u"Swedish"),
(u"th-TH", u"ไทย", u"", u"Thai"),
(u"tr-TR", u"Türkçe", u"", u"Turkish"),
(u"vi-VN", u"Tiếng Việt", u"", u"Vietnamese"),
(u"zh", u"中文", u"", u"Chinese"),
(u"zh-CN", u"中文", u"中国", u"Chinese"),
(u"zh-HK", u"中文", u"香港", u"Chinese"),

View File

@ -189,11 +189,10 @@ engines:
shortcut : et
disabled : True
# api-key required: http://www.faroo.com/hp/api/api.html#key
# - name : faroo
# engine : faroo
# shortcut : fa
# api_key : 'apikey' # required!
- name : faroo
engine : faroo
shortcut : fa
disabled : True
- name : 500px
engine : www500px
@ -247,15 +246,16 @@ engines:
disabled: True
- name : gitlab
engine : xpath
engine : json_engine
paging : True
search_url : https://gitlab.com/search?page={pageno}&search={query}
url_xpath : //li[@class="project-row"]//a[@class="project"]/@href
title_xpath : //li[@class="project-row"]//span[contains(@class, "project-full-name")]
content_xpath : //li[@class="project-row"]//div[@class="description"]/p
search_url : https://gitlab.com/api/v4/projects?search={query}&page={pageno}
url_query : web_url
title_query : name_with_namespace
content_query : description
page_size : 20
categories : it
shortcut : gl
timeout : 5.0
timeout : 10.0
disabled : True
- name : github
@ -326,9 +326,9 @@ engines:
engine : xpath
paging : True
search_url : https://geektimes.ru/search/page{pageno}/?q={query}
url_xpath : //div[@class="search_results"]//a[@class="post__title_link"]/@href
title_xpath : //div[@class="search_results"]//a[@class="post__title_link"]
content_xpath : //div[@class="search_results"]//div[contains(@class, "content")]
url_xpath : //article[contains(@class, "post")]//a[@class="post__title_link"]/@href
title_xpath : //article[contains(@class, "post")]//a[@class="post__title_link"]
content_xpath : //article[contains(@class, "post")]//div[contains(@class, "post__text")]
categories : it
timeout : 4.0
disabled : True
@ -338,9 +338,9 @@ engines:
engine : xpath
paging : True
search_url : https://habrahabr.ru/search/page{pageno}/?q={query}
url_xpath : //div[@class="search_results"]//a[contains(@class, "post__title_link")]/@href
title_xpath : //div[@class="search_results"]//a[contains(@class, "post__title_link")]
content_xpath : //div[@class="search_results"]//div[contains(@class, "content")]
url_xpath : //article[contains(@class, "post")]//a[@class="post__title_link"]/@href
title_xpath : //article[contains(@class, "post")]//a[@class="post__title_link"]
content_xpath : //article[contains(@class, "post")]//div[contains(@class, "post__text")]
categories : it
timeout : 4.0
disabled : True
@ -556,6 +556,12 @@ engines:
timeout : 6.0
disabled : True
- name : torrentz
engine : torrentz
shortcut : tor
url: https://torrentz2.eu/
timeout : 3.0
- name : twitter
engine : twitter
shortcut : tw
@ -579,6 +585,7 @@ engines:
- name : yahoo
engine : yahoo
shortcut : yh
disabled : True
- name : yandex
engine : yandex
@ -639,10 +646,10 @@ engines:
engine: xpath
shortcut: vo
categories: social media
search_url : https://voat.co/search?q={query}
url_xpath : //p[contains(@class, "title")]/a/@href
title_xpath : //p[contains(@class, "title")]/a
content_xpath : //span[@class="domain"]
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"]
timeout : 10.0
disabled : True
@ -651,12 +658,6 @@ engines:
shortcut : 1337x
disabled : True
#The blekko technology and team have joined IBM Watson! -> https://blekko.com/
# - name : blekko images
# engine : blekko_images
# locale : en-US
# shortcut : bli
# - name : yacy
# engine : yacy
# shortcut : ya
@ -676,7 +677,6 @@ locales:
bg : Български (Bulgarian)
cs : Čeština (Czech)
de : Deutsch (German)
de_DE : Deutsch (German_Germany)
el_GR : Ελληνικά (Greek_Greece)
eo : Esperanto (Esperanto)
es : Español (Spanish)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
/*! oscar/searx.min.js | 25-07-2016 | https://github.com/asciimoo/searx */
/*! 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)})});

View File

@ -19,3 +19,5 @@
@import "cursor.less";
@import "code.less";
@import "preferences.less";

View File

@ -0,0 +1,3 @@
.table > tbody > tr > td, .table > tbody > tr > th {
vertical-align: middle !important;
}

View File

@ -17,3 +17,5 @@
@import "code.less";
@import "navbar.less";
@import "preferences.less";

View File

@ -0,0 +1,3 @@
.table > tbody > tr > td, .table > tbody > tr > th {
vertical-align: middle !important;
}

View File

@ -1,11 +1,11 @@
<div class="result {{ result.class }}">
<h3 class="result_title">{% if result['favicon'] %}<img width="14" height="14" class="favicon" src="static/{{theme}}/img/icon_{{result['favicon']}}.ico" alt="{{result['favicon']}}" />{% endif %}<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.publishedDate %}<span class="published_date">{{ result.publishedDate }}</span>{% endif %}
<p class="content">{% if result.img_src %}<img src="{{ image_proxify(result.img_src) }}" class="image" />{% endif %}{% if result.content %}{{ result.content|safe }}<br class="last"/>{% endif %}</p>
{% if result.repository %}<p class="content"><a href="{{ result.repository|safe }}" {% 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>
<p class="url">{{ result.pretty_url }}&lrm;</p>
</div>
<div class="result {{ result.class }}">
<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.publishedDate %}<span class="published_date">{{ result.publishedDate }}</span>{% endif %}
<p class="content">{% if result.img_src %}<img src="{{ image_proxify(result.img_src) }}" class="image" />{% endif %}{% if result.content %}{{ result.content|safe }}<br class="last"/>{% endif %}</p>
{% if result.repository %}<p class="content"><a href="{{ result.repository|safe }}" {% 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>
<p class="url">{{ result.pretty_url }}&lrm;</p>
</div>

View File

@ -1,11 +1,11 @@
<div class="result {{ result.class }}">
<h3 class="result_title"> {% if result['favicon'] %}<img width="14" height="14" class="favicon" src="static/{{theme}}/img/icon_{{result['favicon']}}.ico" alt="{{result['favicon']}}" />{% endif %}<a href="{{ result.url }}" {% if results_on_new_tab %}target="_blank" rel="noopener noreferrer"{% else %}rel="noreferrer"{% endif %}>{{ result.title|safe }}</a></h3>
<p class="url">{{ result.pretty_url }}&lrm; <a class="cache_link" href="https://web.archive.org/web/{{ result.url }}" {% if results_on_new_tab %}target="_blank" rel="noopener noreferrer"{% else %}rel="noreferrer"{% endif %}>{{ _('cached') }}</a></p>
{% if result.publishedDate %}<p class="published_date">{{ result.publishedDate }}</p>{% endif %}
<p class="content">{% if result.img_src %}<img src="{{ image_proxify(result.img_src) }}" class="image" />{% endif %}{% if result.content %}{{ result.content|safe }}<br class="last"/>{% endif %}</p>
{% if result.repository %}<p class="result-content"><a href="{{ result.repository|safe }}" {% 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>
</div>
<div class="result {{ result.class }}">
<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>
<p class="url">{{ result.pretty_url }}&lrm; <a class="cache_link" href="https://web.archive.org/web/{{ result.url }}" {% if results_on_new_tab %}target="_blank" rel="noopener noreferrer"{% else %}rel="noreferrer"{% endif %}>{{ _('cached') }}</a></p>
{% if result.publishedDate %}<p class="published_date">{{ result.publishedDate }}</p>{% endif %}
<p class="content">{% if result.img_src %}<img src="{{ image_proxify(result.img_src) }}" class="image" />{% endif %}{% if result.content %}{{ result.content|safe }}<br class="last"/>{% endif %}</p>
{% if result.repository %}<p class="result-content"><a href="{{ result.repository|safe }}" {% 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>
</div>

View File

@ -1,88 +1,99 @@
<!-- Draw glyphicon icon from bootstrap-theme -->
{% macro icon(action) -%}
<span class="glyphicon glyphicon-{{ action }}"></span>
{%- endmacro %}
<!-- Draw favicon -->
<!-- TODO: using url_for methode -->
{% macro draw_favicon(favicon) -%}
<img width="32" height="32" class="favicon" src="static/themes/oscar/img/icons/{{ favicon }}.png" alt="{{ favicon }}" />
{%- endmacro %}
{%- macro result_link(url, title, classes='') -%}
<a href="{{ url }}" {% if classes %}class="{{ classes }}" {% endif %}{% if results_on_new_tab %}target="_blank" rel="noopener noreferrer"{% else %}rel="noreferrer"{% endif %}>{{ title }}</a>
{%- endmacro -%}
<!-- 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>
{%- endmacro %}
<!-- Draw result sub header -->
{% macro result_sub_header(result) -%}
{% if result.publishedDate %}<time class="text-muted" datetime="{{ result.pubdate }}" >{{ result.publishedDate }}</time>{% endif %}
{% if result.magnetlink %}<small> &bull; {{ result_link(result.magnetlink, icon('magnet') + _('magnet link'), "magnetlink") }}</small>{% endif %}
{% if result.torrentfile %}<small> &bull; {{ result_link(result.torrentfile, icon('download-alt') + _('torrent file'), "torrentfile") }}</small>{% endif %}
{%- endmacro %}
<!-- Draw result footer -->
{% macro result_footer(result) -%}
<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>
{%- endmacro %}
<!-- Draw result footer -->
{% macro result_footer_rtl(result) -%}
<div class="clearfix"></div>
{% 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 class="external-link">{{ result.pretty_url }}</div>
{%- endmacro %}
{% macro preferences_item_header(info, label, rtl) -%}
{% if rtl %}
<div class="row form-group">
<label class="col-sm-3 col-md-2 pull-right">{{ label }}</label>
<span class="col-sm-5 col-md-6 help-block pull-left">{{ info }}</span>
<div class="col-sm-4 col-md-4">
{% else %}
<div class="row form-group">
<label class="col-sm-3 col-md-2">{{ label }}</label>
<div class="col-sm-4 col-md-4">
{% endif %}
{%- endmacro %}
{% macro preferences_item_footer(info, label, rtl) -%}
{% if rtl %}
</div>
</div>
{% else %}
</div>
<span class="col-sm-5 col-md-6 help-block">{{ info }}</span>
</div>
{% endif %}
{%- endmacro %}
{% macro checkbox_toggle(id, blocked) -%}
<div class="onoffswitch">
<input type="checkbox" id="{{ id }}" name="{{ id }}"{% if blocked %} checked="checked"{% endif %} class="onoffswitch-checkbox">
<label class="onoffswitch-label" for="{{ id }}">
<span class="onoffswitch-inner"></span>
<span class="onoffswitch-switch"></span>
</label>
</div>
{%- endmacro %}
<!-- Draw glyphicon icon from bootstrap-theme -->
{% macro icon(action) -%}
<span class="glyphicon glyphicon-{{ action }}"></span>
{%- endmacro %}
<!-- Draw favicon -->
{% macro draw_favicon(favicon) -%}
<img width="32" height="32" class="favicon" src="{{ url_for('static', filename='themes/oscar/img/icons/' + favicon + '.png') }}" alt="{{ favicon }}" />
{%- endmacro %}
{%- macro result_link(url, title, classes='') -%}
<a href="{{ url }}" {% if classes %}class="{{ classes }}" {% endif %}{% if results_on_new_tab %}target="_blank" rel="noopener noreferrer"{% else %}rel="noreferrer"{% endif %}>{{ title }}</a>
{%- endmacro -%}
<!-- 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>
{%- endmacro %}
<!-- Draw result sub header -->
{% macro result_sub_header(result) -%}
{% if result.publishedDate %}<time class="text-muted" datetime="{{ result.pubdate }}" >{{ result.publishedDate }}</time>{% endif %}
{% if result.magnetlink %}<small> &bull; {{ result_link(result.magnetlink, icon('magnet') + _('magnet link'), "magnetlink") }}</small>{% endif %}
{% if result.torrentfile %}<small> &bull; {{ result_link(result.torrentfile, icon('download-alt') + _('torrent file'), "torrentfile") }}</small>{% endif %}
{%- endmacro %}
<!-- Draw result footer -->
{% macro result_footer(result) -%}
<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>
{%- endmacro %}
<!-- Draw result footer -->
{% macro result_footer_rtl(result) -%}
<div class="clearfix"></div>
{% 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 class="external-link">{{ result.pretty_url }}</div>
{%- endmacro %}
{% macro preferences_item_header(info, label, rtl) -%}
{% if rtl %}
<div class="row form-group">
<label class="col-sm-3 col-md-2 pull-right">{{ label }}</label>
<span class="col-sm-5 col-md-6 help-block pull-left">{{ info }}</span>
<div class="col-sm-4 col-md-4">
{% else %}
<div class="row form-group">
<label class="col-sm-3 col-md-2">{{ label }}</label>
<div class="col-sm-4 col-md-4">
{% endif %}
{%- endmacro %}
{% macro preferences_item_footer(info, label, rtl) -%}
{% if rtl %}
</div>
</div>
{% else %}
</div>
<span class="col-sm-5 col-md-6 help-block">{{ info }}</span>
</div>
{% endif %}
{%- endmacro %}
{% macro checkbox_toggle(id, blocked) -%}
<div class="onoffswitch">
<input type="checkbox" id="{{ id }}" name="{{ id }}"{% if blocked %} checked="checked"{% endif %} class="onoffswitch-checkbox">
<label class="onoffswitch-label" for="{{ id }}">
<span class="onoffswitch-inner"></span>
<span class="onoffswitch-switch"></span>
</label>
</div>
{%- endmacro %}
{% macro support_toggle(supports) -%}
{% if supports %}
<span class="label label-success">
{{ _("supported") }}
</span>
{% else %}
<span class="label label-danger">
{{ _("not supported") }}
</span>
{% endif %}
{%- endmacro %}

View File

@ -1,7 +1,8 @@
{% from 'oscar/macros.html' import preferences_item_header, preferences_item_header_rtl, preferences_item_footer, preferences_item_footer_rtl, checkbox_toggle %}
{% from 'oscar/macros.html' import preferences_item_header, preferences_item_header_rtl, preferences_item_footer, preferences_item_footer_rtl, checkbox_toggle, support_toggle %}
{% extends "oscar/base.html" %}
{% block title %}{{ _('preferences') }} - {% endblock %}
{% block content %}
<div>
<h1>{{ _('Preferences') }}</h1>
@ -148,7 +149,7 @@
<th>{{ _("Allow") }}</th>
<th>{{ _("Engine name") }}</th>
<th>{{ _("Shortcut") }}</th>
<th>{{ _("Supports selected language") }}</th>
<th>{{ _("Selected language") }}</th>
<th>{{ _("SafeSearch") }}</th>
<th>{{ _("Time range") }}</th>
<th>{{ _("Avg. time") }}</th>
@ -156,8 +157,9 @@
{% else %}
<th>{{ _("Max time") }}</th>
<th>{{ _("Avg. time") }}</th>
<th>{{ _("Time range") }}</th>
<th>{{ _("SafeSearch") }}</th>
<th>{{ _("Supports selected language") }}</th>
<th>{{ _("Selected language") }}</th>
<th>{{ _("Shortcut") }}</th>
<th>{{ _("Engine name") }}</th>
<th>{{ _("Allow") }}</th>
@ -172,17 +174,18 @@
</td>
<th>{{ search_engine.name }}</th>
<td class="name">{{ shortcuts[search_engine.name] }}</td>
<td><input type="checkbox" {{ "checked" if current_language == 'all' or current_language in search_engine.supported_languages or current_language.split('-')[0] in search_engine.supported_languages else ""}} readonly="readonly" disabled="disabled"></td>
<td><input type="checkbox" {{ "checked" if search_engine.safesearch==True else ""}} readonly="readonly" disabled="disabled"></td>
<td><input type="checkbox" {{ "checked" if search_engine.time_range_support==True else ""}} readonly="readonly" disabled="disabled"></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><input type="checkbox" {{ "checked" if search_engine.safesearch==True else ""}} readonly="readonly" disabled="disabled"></td>
<td><input type="checkbox" {{ "checked" if current_language == 'all' or current_language in search_engine.supported_languages or current_language.split('-')[0] in search_engine.supported_languages else ""}} readonly="readonly" disabled="disabled"></td>
<td>{{ shortcuts[search_engine.name] }}</td>
<td>{{ support_toggle(current_language == 'all' or current_language in search_engine.supported_languages or current_language.split('-')[0] in search_engine.supported_languages) }}</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(current_language == 'all' or current_language in search_engine.supported_languages or current_language.split('-')[0] in search_engine.supported_languages) }}</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) }}

View File

@ -8,9 +8,8 @@
{%- endmacro %}
<!-- Draw favicon -->
<!-- TODO: using url_for methode -->
{% macro draw_favicon(favicon) -%}
<img width="14" height="14" class="favicon" src="static/themes/simple/img/icons/{{ favicon }}.png" alt="{{ favicon }}" />
<img width="14" height="14" class="favicon" src="{{ url_for('static', filename='themes/simple/img/icons/' + favicon + '.png') }}" alt="{{ favicon }}" />
{%- endmacro %}
{% macro result_open_link(url, classes='') -%}

View File

@ -1,844 +0,0 @@
# Translations template for PROJECT.
# Copyright (C) 2016 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
#
# Translators:
# Bamstam, 2016-2017
# Benjamin Richter <benjamin@hacktherack.de>, 2015
# cy8aer <cybaer42@web.de>, 2016-2017
msgid ""
msgstr ""
"Project-Id-Version: searx\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2016-12-29 10:42+0100\n"
"PO-Revision-Date: 2017-05-19 20:17+0000\n"
"Last-Translator: cy8aer <cybaer42@web.de>\n"
"Language-Team: German (Germany) (http://www.transifex.com/asciimoo/searx/language/de_DE/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.3.4\n"
"Language: de_DE\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: searx/webapp.py:123
msgid "files"
msgstr "Dateien"
#: searx/webapp.py:124
msgid "general"
msgstr "Allgemein"
#: searx/webapp.py:125
msgid "music"
msgstr "Musik"
#: searx/webapp.py:126
msgid "social media"
msgstr "Soziale Medien"
#: searx/webapp.py:127
msgid "images"
msgstr "Fotos"
#: searx/webapp.py:128
msgid "videos"
msgstr "Videos"
#: searx/webapp.py:129
msgid "it"
msgstr "IT"
#: searx/webapp.py:130
msgid "news"
msgstr "Nachrichten"
#: searx/webapp.py:131
msgid "map"
msgstr "Karten"
#: searx/webapp.py:132
msgid "science"
msgstr "Wissenschaft"
#: searx/webapp.py:384 searx/webapp.py:594
msgid "Invalid settings, please edit your preferences"
msgstr "Ungültige Auswahl, bitte überprüfen Sie die Einstellungen"
#: searx/webapp.py:425
msgid "search error"
msgstr "Fehler bei der Suche"
#: searx/webapp.py:467
msgid "{minutes} minute(s) ago"
msgstr "vor {minutes} Minute(n)"
#: searx/webapp.py:469
msgid "{hours} hour(s), {minutes} minute(s) ago"
msgstr "vor {hours} Stunde(n). {minutes} Minute(n)"
#: searx/answerers/random/answerer.py:48
msgid "Random value generator"
msgstr "Zufallswertgenerator"
#: searx/answerers/random/answerer.py:49
msgid "Generate different random values"
msgstr "Zufallswerte generieren"
#: searx/answerers/statistics/answerer.py:49
msgid "Statistics functions"
msgstr "Statistik-Funktionen"
#: searx/answerers/statistics/answerer.py:50
msgid "Compute {functions} of the arguments"
msgstr "{functions} der Argumente berechnen"
#: searx/engines/__init__.py:192
msgid "Engine time (sec)"
msgstr "Zeitbedarf (s)"
#: searx/engines/__init__.py:196
msgid "Page loads (sec)"
msgstr "Ladezeit (s)"
#: searx/engines/__init__.py:200 searx/templates/oscar/results.html:88
msgid "Number of results"
msgstr "Anzahl Ergebnisse"
#: searx/engines/__init__.py:204
msgid "Scores"
msgstr "Punktwerte"
#: searx/engines/__init__.py:208
msgid "Scores per result"
msgstr "Punktwerte pro Ergebnis"
#: searx/engines/__init__.py:212
msgid "Errors"
msgstr "Fehler"
#: searx/engines/pdbe.py:87
msgid "{title}&nbsp;(OBSOLETE)"
msgstr "{title}&nbsp;(OBSOLET)"
#: searx/engines/pdbe.py:91
msgid "This entry has been superseded by"
msgstr "Dieser Eintrag wurde ersetzt durch"
#: searx/plugins/doai_rewrite.py:7
msgid "DOAI rewrite"
msgstr "DOAI-Umgehung"
#: searx/plugins/doai_rewrite.py:8
msgid ""
"Avoid paywalls by redirecting to open-access versions of publications when "
"available"
msgstr "Paywalls umgehen, indem wenn möglich auf Open-Access-Versionen von Publikationen umgeleitet wird"
#: searx/plugins/https_rewrite.py:29
msgid "Rewrite HTTP links to HTTPS if possible"
msgstr "Umschreiben von HTTP-Links nach HTTPS, wenn möglich"
#: searx/plugins/infinite_scroll.py:3
msgid "Infinite scroll"
msgstr "Unbegrenztes Scrollen"
#: searx/plugins/infinite_scroll.py:4
msgid "Automatically load next page when scrolling to bottom of current page"
msgstr "Nächste Seite automatisch laden, wenn zum Seitenende gescrollt wird"
#: searx/plugins/open_results_on_new_tab.py:18
#: searx/templates/oscar/preferences.html:113
msgid "Open result links on new browser tabs"
msgstr "Öffne Links in einem neuen Browser-Tab"
#: searx/plugins/open_results_on_new_tab.py:19
msgid ""
"Results are opened in the same window by default. This plugin overwrites the"
" default behaviour to open links on new tabs/windows. (JavaScript required)"
msgstr "Suchergebnisse werden standardmäßig im gleichen Fenster geöffnet. Dieses Plug-in überschreibt dieses Standardverhalten und öffnet Links in neuen Tabs/Fenstern (benötigt JavaScript)."
#: searx/plugins/search_on_category_select.py:18
msgid "Search on category select"
msgstr "Suchen nach Kategorie"
#: searx/plugins/search_on_category_select.py:19
msgid ""
"Perform search immediately if a category selected. Disable to select "
"multiple categories. (JavaScript required)"
msgstr "Suche sofort durchführen, wenn eine Kategorie ausgewählt wird. Deaktivieren Sie diese Option, um mehrere Kategorien auswählen zu können (benötigt JavaScript)."
#: searx/plugins/self_info.py:20
msgid ""
"Displays your IP if the query is \"ip\" and your user agent if the query "
"contains \"user agent\"."
msgstr "Zeigt Ihre IP-Adresse an, wenn \"ip\" als Suchanfrage eingegeben wird und den User Agent bzw. das verwendete Client-Programm, wenn die Suchanfrage den Ausdruck \"user agent\" enthält."
#: searx/plugins/tracker_url_remover.py:26
msgid "Tracker URL remover"
msgstr "Tracking-URLs bereinigen"
#: searx/plugins/tracker_url_remover.py:27
msgid "Remove trackers arguments from the returned URL"
msgstr "Tracker-Argumente der erhaltenen URL entfernen"
#: searx/plugins/vim_hotkeys.py:3
msgid "Vim-like hotkeys"
msgstr "Vim-ähnliche Hotkeys"
#: searx/plugins/vim_hotkeys.py:4
msgid ""
"Navigate search results with Vim-like hotkeys (JavaScript required). Press "
"\"h\" key on main or result page to get help."
msgstr "Durch Suchergebnisse navigieren mit Vim-ähnlichen Hotkeys (benötigt JavaScript). \"h\" drücken auf der Hauptseite oder der Ergebnisseite, um Hilfe zu erhalten."
#: searx/templates/courgette/404.html:4 searx/templates/legacy/404.html:4
#: searx/templates/oscar/404.html:4 searx/templates/pix-art/404.html:4
msgid "Page not found"
msgstr "Seite nicht gefunden"
#: searx/templates/courgette/404.html:6 searx/templates/legacy/404.html:6
#: searx/templates/oscar/404.html:6 searx/templates/pix-art/404.html:6
#, python-format
msgid "Go to %(search_page)s."
msgstr "Gehe zu %(search_page)s."
#: searx/templates/courgette/404.html:6 searx/templates/legacy/404.html:6
#: searx/templates/oscar/404.html:6 searx/templates/pix-art/404.html:6
msgid "search page"
msgstr "Seite durchsuchen"
#: searx/templates/courgette/index.html:9
#: searx/templates/courgette/index.html:13
#: searx/templates/courgette/results.html:5
#: searx/templates/legacy/index.html:8 searx/templates/legacy/index.html:12
#: searx/templates/oscar/navbar.html:12
#: searx/templates/oscar/preferences.html:3
#: searx/templates/pix-art/index.html:8
msgid "preferences"
msgstr "Einstellungen"
#: searx/templates/courgette/index.html:11
#: searx/templates/legacy/index.html:10 searx/templates/oscar/about.html:2
#: searx/templates/oscar/navbar.html:11 searx/templates/pix-art/index.html:7
msgid "about"
msgstr "Über uns"
#: searx/templates/courgette/preferences.html:5
#: searx/templates/legacy/preferences.html:5
#: searx/templates/oscar/preferences.html:7
#: searx/templates/pix-art/preferences.html:5
msgid "Preferences"
msgstr "Einstellungen"
#: searx/templates/courgette/preferences.html:9
#: searx/templates/legacy/preferences.html:9
#: searx/templates/oscar/preferences.html:32
#: searx/templates/oscar/preferences.html:34
msgid "Default categories"
msgstr "Standardkategorien"
#: searx/templates/courgette/preferences.html:13
#: searx/templates/legacy/preferences.html:14
#: searx/templates/oscar/preferences.html:40
#: searx/templates/pix-art/preferences.html:9
msgid "Search language"
msgstr "Suchsprache"
#: searx/templates/courgette/preferences.html:16
#: searx/templates/legacy/preferences.html:17
#: searx/templates/oscar/languages.html:6
#: searx/templates/pix-art/preferences.html:12
msgid "Default language"
msgstr "Standardsprache"
#: searx/templates/courgette/preferences.html:24
#: searx/templates/legacy/preferences.html:25
#: searx/templates/oscar/preferences.html:46
#: searx/templates/pix-art/preferences.html:20
msgid "Interface language"
msgstr "Sprache der Benutzeroberfläche"
#: searx/templates/courgette/preferences.html:34
#: searx/templates/legacy/preferences.html:35
#: searx/templates/oscar/preferences.html:56
msgid "Autocomplete"
msgstr "Autovervollständigen"
#: searx/templates/courgette/preferences.html:45
#: searx/templates/legacy/preferences.html:46
#: searx/templates/oscar/preferences.html:67
msgid "Image proxy"
msgstr "Proxy-Server für Bilder"
#: searx/templates/courgette/preferences.html:48
#: searx/templates/legacy/preferences.html:49
#: searx/templates/oscar/preferences.html:71
msgid "Enabled"
msgstr "Aktiviert"
#: searx/templates/courgette/preferences.html:49
#: searx/templates/legacy/preferences.html:50
#: searx/templates/oscar/preferences.html:72
msgid "Disabled"
msgstr "Deaktiviert"
#: searx/templates/courgette/preferences.html:54
#: searx/templates/legacy/preferences.html:55
#: searx/templates/oscar/preferences.html:76
#: searx/templates/pix-art/preferences.html:30
msgid "Method"
msgstr "Methode"
#: searx/templates/courgette/preferences.html:63
#: searx/templates/legacy/preferences.html:64
#: searx/templates/oscar/preferences.html:85
#: searx/templates/oscar/preferences.html:152
#: searx/templates/oscar/preferences.html:159
msgid "SafeSearch"
msgstr "SafeSearch"
#: searx/templates/courgette/preferences.html:66
#: searx/templates/legacy/preferences.html:67
#: searx/templates/oscar/preferences.html:89
msgid "Strict"
msgstr "Streng"
#: searx/templates/courgette/preferences.html:67
#: searx/templates/legacy/preferences.html:68
#: searx/templates/oscar/preferences.html:90
msgid "Moderate"
msgstr "Moderat"
#: searx/templates/courgette/preferences.html:68
#: searx/templates/legacy/preferences.html:69
#: searx/templates/oscar/preferences.html:91
msgid "None"
msgstr "Keine"
#: searx/templates/courgette/preferences.html:73
#: searx/templates/legacy/preferences.html:74
#: searx/templates/oscar/preferences.html:95
#: searx/templates/pix-art/preferences.html:39
msgid "Themes"
msgstr "Oberflächen"
#: searx/templates/courgette/preferences.html:83
msgid "Color"
msgstr "Farbe"
#: searx/templates/courgette/preferences.html:86
msgid "Blue (default)"
msgstr "Blau (Standard)"
#: searx/templates/courgette/preferences.html:87
msgid "Violet"
msgstr "Violett"
#: searx/templates/courgette/preferences.html:88
msgid "Green"
msgstr "Grün"
#: searx/templates/courgette/preferences.html:89
msgid "Cyan"
msgstr "Türkis"
#: searx/templates/courgette/preferences.html:90
msgid "Orange"
msgstr "Orange"
#: searx/templates/courgette/preferences.html:91
msgid "Red"
msgstr "Rot"
#: searx/templates/courgette/preferences.html:96
#: searx/templates/legacy/preferences.html:93
#: searx/templates/pix-art/preferences.html:49
msgid "Currently used search engines"
msgstr "Momentan genutzte Suchmaschinen"
#: searx/templates/courgette/preferences.html:100
#: searx/templates/legacy/preferences.html:97
#: searx/templates/oscar/preferences.html:149
#: searx/templates/oscar/preferences.html:162
#: searx/templates/pix-art/preferences.html:53
msgid "Engine name"
msgstr "Suchmaschinen-Name"
#: searx/templates/courgette/preferences.html:101
#: searx/templates/legacy/preferences.html:98
msgid "Category"
msgstr "Kategorie"
#: searx/templates/courgette/preferences.html:102
#: searx/templates/courgette/preferences.html:113
#: searx/templates/legacy/preferences.html:99
#: searx/templates/legacy/preferences.html:110
#: searx/templates/oscar/preferences.html:148
#: searx/templates/oscar/preferences.html:163
#: searx/templates/pix-art/preferences.html:54
#: searx/templates/pix-art/preferences.html:64
msgid "Allow"
msgstr "Zulassen"
#: searx/templates/courgette/preferences.html:102
#: searx/templates/courgette/preferences.html:114
#: searx/templates/legacy/preferences.html:99
#: searx/templates/legacy/preferences.html:111
#: searx/templates/pix-art/preferences.html:54
#: searx/templates/pix-art/preferences.html:65
msgid "Block"
msgstr "Blockieren"
#: searx/templates/courgette/preferences.html:122
#: searx/templates/legacy/preferences.html:119
#: searx/templates/oscar/preferences.html:282
#: searx/templates/pix-art/preferences.html:73
msgid ""
"These settings are stored in your cookies, this allows us not to store this "
"data about you."
msgstr "Diese Einstellungen werden in Ihren Cookies gespeichert, deshalb müssen wir diese persönlichen Daten nicht bei uns speichern."
#: searx/templates/courgette/preferences.html:124
#: searx/templates/legacy/preferences.html:121
#: searx/templates/oscar/preferences.html:284
#: searx/templates/pix-art/preferences.html:75
msgid ""
"These cookies serve your sole convenience, we don't use these cookies to "
"track you."
msgstr "Diese Cookies ermöglichen lediglich eine komfortablere Nutzung, wir verwenden diese Cookies nicht, um Sie zu tracken."
#: searx/templates/courgette/preferences.html:127
#: searx/templates/legacy/preferences.html:124
#: searx/templates/oscar/preferences.html:287
#: searx/templates/pix-art/preferences.html:78
msgid "save"
msgstr "speichern"
#: searx/templates/courgette/preferences.html:128
#: searx/templates/legacy/preferences.html:125
#: searx/templates/oscar/preferences.html:289
msgid "Reset defaults"
msgstr "Voreinstellungen wiederherstellen"
#: searx/templates/courgette/preferences.html:129
#: searx/templates/legacy/preferences.html:126
#: searx/templates/oscar/preferences.html:288
#: searx/templates/pix-art/preferences.html:79
msgid "back"
msgstr "zurück"
#: searx/templates/courgette/results.html:12
#: searx/templates/legacy/results.html:13
#: searx/templates/oscar/results.html:124
msgid "Search URL"
msgstr "Such-URL"
#: searx/templates/courgette/results.html:16
#: searx/templates/legacy/results.html:17
#: searx/templates/oscar/results.html:129
msgid "Download results"
msgstr "Suchergebnisse herunterladen"
#: searx/templates/courgette/results.html:34
#: searx/templates/legacy/results.html:35
msgid "Answers"
msgstr "Antworten"
#: searx/templates/courgette/results.html:42
#: searx/templates/legacy/results.html:43
#: searx/templates/oscar/results.html:104
msgid "Suggestions"
msgstr "Vorschläge"
#: searx/templates/courgette/results.html:70
#: searx/templates/legacy/results.html:81
#: searx/templates/oscar/results.html:53 searx/templates/oscar/results.html:66
msgid "previous page"
msgstr "vorherige Seite"
#: searx/templates/courgette/results.html:81
#: searx/templates/legacy/results.html:92
#: searx/templates/oscar/results.html:45 searx/templates/oscar/results.html:75
msgid "next page"
msgstr "nächste Seite"
#: searx/templates/courgette/search.html:3
#: searx/templates/legacy/search.html:3 searx/templates/oscar/search.html:4
#: searx/templates/oscar/search_full.html:9
#: searx/templates/pix-art/search.html:3
msgid "Search for..."
msgstr "Suchen nach ..."
#: searx/templates/courgette/stats.html:4 searx/templates/legacy/stats.html:4
#: searx/templates/oscar/stats.html:5 searx/templates/pix-art/stats.html:4
msgid "Engine stats"
msgstr "Suchmaschinen-Statistiken"
#: searx/templates/courgette/result_templates/images.html:4
#: searx/templates/legacy/result_templates/images.html:4
#: searx/templates/pix-art/result_templates/images.html:4
msgid "original context"
msgstr "Ursprünglicher Kontext"
#: searx/templates/courgette/result_templates/torrent.html:7
#: searx/templates/legacy/result_templates/torrent.html:11
#: searx/templates/oscar/result_templates/torrent.html:6
msgid "Seeder"
msgstr "Seeder"
#: searx/templates/courgette/result_templates/torrent.html:7
#: searx/templates/legacy/result_templates/torrent.html:11
#: searx/templates/oscar/result_templates/torrent.html:6
msgid "Leecher"
msgstr "Leecher"
#: searx/templates/courgette/result_templates/torrent.html:9
#: searx/templates/legacy/result_templates/torrent.html:9
#: searx/templates/oscar/macros.html:24
msgid "magnet link"
msgstr "Magnet-Link"
#: searx/templates/courgette/result_templates/torrent.html:10
#: searx/templates/legacy/result_templates/torrent.html:10
#: searx/templates/oscar/macros.html:25
msgid "torrent file"
msgstr "Torrent-Datei"
#: searx/templates/legacy/categories.html:8
msgid "Click on the magnifier to perform search"
msgstr "Klicken Sie auf das Vergrößerungsglas, um die Suche zu starten"
#: searx/templates/legacy/preferences.html:84
#: searx/templates/oscar/preferences.html:112
msgid "Results on new tabs"
msgstr "Ergebnisse in neuen Tabs"
#: searx/templates/legacy/preferences.html:87
#: searx/templates/oscar/preferences.html:116
msgid "On"
msgstr "An"
#: searx/templates/legacy/preferences.html:88
#: searx/templates/oscar/preferences.html:117
msgid "Off"
msgstr "Aus"
#: searx/templates/legacy/result_templates/code.html:3
#: searx/templates/legacy/result_templates/default.html:3
#: searx/templates/legacy/result_templates/map.html:9
#: searx/templates/oscar/macros.html:35 searx/templates/oscar/macros.html:49
msgid "cached"
msgstr "im Cache"
#: searx/templates/oscar/advanced.html:4
msgid "Advanced settings"
msgstr "Erweiterte Einstellungen"
#: searx/templates/oscar/base.html:62
#: searx/templates/oscar/messages/first_time.html:4
#: searx/templates/oscar/messages/no_results.html:5
#: searx/templates/oscar/messages/save_settings_successfull.html:5
#: searx/templates/oscar/messages/unknow_error.html:5
msgid "Close"
msgstr "Schließen"
#: searx/templates/oscar/base.html:64
msgid "Error!"
msgstr "Fehler!"
#: searx/templates/oscar/base.html:90
msgid "Powered by"
msgstr "Bereitgestellt von"
#: searx/templates/oscar/base.html:90
msgid "a privacy-respecting, hackable metasearch engine"
msgstr "eine die Privatsphäre respektierende, hackbare Meta-Suchmaschine"
#: searx/templates/oscar/macros.html:37 searx/templates/oscar/macros.html:51
msgid "proxied"
msgstr "via Proxy-Server"
#: searx/templates/oscar/preferences.html:12
#: searx/templates/oscar/preferences.html:21
msgid "General"
msgstr "Allgemein"
#: searx/templates/oscar/preferences.html:13
#: searx/templates/oscar/preferences.html:133
msgid "Engines"
msgstr "Suchmaschinen"
#: searx/templates/oscar/preferences.html:14
#: searx/templates/oscar/preferences.html:204
msgid "Plugins"
msgstr "Plug-ins"
#: searx/templates/oscar/preferences.html:15
#: searx/templates/oscar/preferences.html:230
msgid "Answerers"
msgstr "Instant Answers/Sofortantworten"
#: searx/templates/oscar/preferences.html:16
#: searx/templates/oscar/preferences.html:257
msgid "Cookies"
msgstr "Cookies"
#: searx/templates/oscar/preferences.html:41
msgid "What language do you prefer for search?"
msgstr "Welche Sprache möchten Sie für die Suche verwenden?"
#: searx/templates/oscar/preferences.html:47
msgid "Change the language of the layout"
msgstr "Sprache des Layouts ändern"
#: searx/templates/oscar/preferences.html:57
msgid "Find stuff as you type"
msgstr "Bereits während der Eingabe suchen"
#: searx/templates/oscar/preferences.html:68
msgid "Proxying image results through searx"
msgstr "Bilder-Suchergebnisse über den searx-Proxy-Server laden"
#: searx/templates/oscar/preferences.html:77
msgid ""
"Change how forms are submited, <a "
"href=\"http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_methods\""
" rel=\"external\">learn more about request methods</a>"
msgstr "HTTP-Anfragemethode ändern <a href=\"https://de.wikipedia.org/wiki/Hypertext_Transfer_Protocol#HTTP-Anfragemethoden\" rel=\"external\">(weiterführende Informationen zu HTTP-Anfragemethoden)</a>"
#: searx/templates/oscar/preferences.html:86
msgid "Filter content"
msgstr "Inhalte filtern"
#: searx/templates/oscar/preferences.html:96
msgid "Change searx layout"
msgstr "searx-Layout ändern"
#: searx/templates/oscar/preferences.html:105
#: searx/templates/oscar/preferences.html:110
msgid "Choose style for this theme"
msgstr "Stilrichtung für diese Benutzeroberfläche auswählen"
#: searx/templates/oscar/preferences.html:105
#: searx/templates/oscar/preferences.html:110
msgid "Style"
msgstr "Stilrichtung"
#: searx/templates/oscar/preferences.html:150
#: searx/templates/oscar/preferences.html:161
msgid "Shortcut"
msgstr "Kürzel"
#: searx/templates/oscar/preferences.html:151
#: searx/templates/oscar/preferences.html:160
msgid "Supports selected language"
msgstr "Unterstützt die ausgewähle Sprache"
#: searx/templates/oscar/preferences.html:153
msgid "Time range"
msgstr "Zeitraum"
#: searx/templates/oscar/preferences.html:154
#: searx/templates/oscar/preferences.html:158
msgid "Avg. time"
msgstr "Durchschn. Zeit"
#: searx/templates/oscar/preferences.html:155
#: searx/templates/oscar/preferences.html:157
msgid "Max time"
msgstr "Maximale Zeit"
#: searx/templates/oscar/preferences.html:233
msgid "This is the list of searx's instant answering modules."
msgstr "Auflistung der searx-Module für Sofortantworten:"
#: searx/templates/oscar/preferences.html:237
msgid "Name"
msgstr "Name"
#: searx/templates/oscar/preferences.html:238
msgid "Keywords"
msgstr "Schlüsselwörter"
#: searx/templates/oscar/preferences.html:239
msgid "Description"
msgstr "Beschreibung"
#: searx/templates/oscar/preferences.html:240
msgid "Examples"
msgstr "Beispiele"
#: searx/templates/oscar/preferences.html:260
msgid ""
"This is the list of cookies and their values searx is storing on your "
"computer."
msgstr "Hier werden die Cookies und die gespeicherten Cookie-Informationen aufgelistet, die searx auf Ihrem Computer speichert."
#: searx/templates/oscar/preferences.html:261
msgid "With that list, you can assess searx transparency."
msgstr "Mit Hilfe dieser Auflistung können Sie die Transparenz der searx-Suche einschätzen."
#: searx/templates/oscar/preferences.html:266
msgid "Cookie name"
msgstr "Cookie-Name"
#: searx/templates/oscar/preferences.html:267
msgid "Value"
msgstr "Wert"
#: searx/templates/oscar/results.html:7
msgid "Search results"
msgstr "Durchsuche Ergebnisse"
#: searx/templates/oscar/results.html:119
msgid "Links"
msgstr "Links"
#: searx/templates/oscar/search.html:6
#: searx/templates/oscar/search_full.html:11
msgid "Start search"
msgstr "Suche starten"
#: searx/templates/oscar/stats.html:2
msgid "stats"
msgstr "Statistiken"
#: searx/templates/oscar/time-range.html:3
msgid "Anytime"
msgstr "Beliebiger Zeitunkt"
#: searx/templates/oscar/time-range.html:6
msgid "Last day"
msgstr "Gestern"
#: searx/templates/oscar/time-range.html:9
msgid "Last week"
msgstr "Letzte Woche"
#: searx/templates/oscar/time-range.html:12
msgid "Last month"
msgstr "Letzter Monat"
#: searx/templates/oscar/time-range.html:15
msgid "Last year"
msgstr "Letztes Jahr"
#: searx/templates/oscar/messages/first_time.html:6
#: searx/templates/oscar/messages/no_data_available.html:3
msgid "Heads up!"
msgstr "Aufgepasst!"
#: searx/templates/oscar/messages/first_time.html:7
msgid "It look like you are using searx first time."
msgstr "Anscheinend benutzen Sie searx zum ersten Mal."
#: searx/templates/oscar/messages/no_cookies.html:3
msgid "Information!"
msgstr "Zur Information!"
#: searx/templates/oscar/messages/no_cookies.html:4
msgid "currently, there are no cookies defined."
msgstr "Zur Zeit sind keine Cookies definiert."
#: searx/templates/oscar/messages/no_data_available.html:4
msgid "There is currently no data available. "
msgstr "Zur Zeit sind keine Daten verfügbar."
#: searx/templates/oscar/messages/no_results.html:7
msgid "Sorry!"
msgstr "Entschuldigung!"
#: searx/templates/oscar/messages/no_results.html:8
msgid ""
"we didn't find any results. Please use another query or search in more "
"categories."
msgstr "Leider konnten wir keine Suchergebnisse finden. Bitte verwenden Sie eine andere Suchabfrage oder erweitern Sie die Suche auf mehr Kategorien."
#: searx/templates/oscar/messages/save_settings_successfull.html:7
msgid "Well done!"
msgstr "Gut gemacht!"
#: searx/templates/oscar/messages/save_settings_successfull.html:8
msgid "Settings saved successfully."
msgstr "Einstellungen erfolgreich gespeichert."
#: searx/templates/oscar/messages/unknow_error.html:7
msgid "Oh snap!"
msgstr "Hoppla!"
#: searx/templates/oscar/messages/unknow_error.html:8
msgid "Something went wrong."
msgstr "Ein Fehler ist aufgetreten."
#: searx/templates/oscar/result_templates/default.html:7
msgid "show media"
msgstr "Medien anzeigen"
#: searx/templates/oscar/result_templates/default.html:7
msgid "hide media"
msgstr "Medien verbergen"
#: searx/templates/oscar/result_templates/images.html:30
msgid "Get image"
msgstr "Bild herunterladen"
#: searx/templates/oscar/result_templates/images.html:33
msgid "View source"
msgstr "Quelle anzeigen"
#: searx/templates/oscar/result_templates/map.html:7
msgid "show map"
msgstr "Karte anzeigen"
#: searx/templates/oscar/result_templates/map.html:7
msgid "hide map"
msgstr "Karte verbergen"
#: searx/templates/oscar/result_templates/map.html:11
msgid "show details"
msgstr "Details anzeigen"
#: searx/templates/oscar/result_templates/map.html:11
msgid "hide details"
msgstr "Details verbergen"
#: searx/templates/oscar/result_templates/torrent.html:7
msgid "Filesize"
msgstr "Dateigröße"
#: searx/templates/oscar/result_templates/torrent.html:9
msgid "Bytes"
msgstr "Bytes"
#: searx/templates/oscar/result_templates/torrent.html:10
msgid "kiB"
msgstr "kiB"
#: searx/templates/oscar/result_templates/torrent.html:11
msgid "MiB"
msgstr "MiB"
#: searx/templates/oscar/result_templates/torrent.html:12
msgid "GiB"
msgstr "GiB"
#: searx/templates/oscar/result_templates/torrent.html:13
msgid "TiB"
msgstr "TiB"
#: searx/templates/oscar/result_templates/torrent.html:15
msgid "Number of Files"
msgstr "Anzahl Dateien"
#: searx/templates/oscar/result_templates/videos.html:7
msgid "show video"
msgstr "Video anzeigen"
#: searx/templates/oscar/result_templates/videos.html:7
msgid "hide video"
msgstr "Video verbergen"
#: searx/templates/pix-art/results.html:28
msgid "Load more..."
msgstr "Mehr anzeigen ..."

View File

@ -1,4 +1,6 @@
import csv
import hashlib
import hmac
import os
import re
@ -290,6 +292,15 @@ def convert_str_to_int(number_str):
return 0
# convert a variable to integer or return 0 if it's not a number
def int_or_zero(num):
if isinstance(num, list):
if len(num) < 1:
return 0
num = num[0]
return convert_str_to_int(num)
def is_valid_lang(lang):
is_abbr = (len(lang) == 2)
if is_abbr:
@ -312,3 +323,10 @@ def load_module(filename, module_dir):
module = load_source(modname, filepath)
module.name = modname
return module
def new_hmac(secret_key, url):
if sys.version_info[0] == 2:
return hmac.new(bytes(secret_key), url, hashlib.sha256).hexdigest()
else:
return hmac.new(bytes(secret_key, 'utf-8'), url, hashlib.sha256).hexdigest()

View File

@ -69,6 +69,7 @@ from searx.plugins import plugins
from searx.preferences import Preferences, ValidationException
from searx.answerers import answerers
from searx.url_utils import urlencode, urlparse, urljoin
from searx.utils import new_hmac
# check if the pyopenssl package is installed.
# It is needed for SSL connection without trouble, see #298
@ -290,7 +291,7 @@ def image_proxify(url):
if settings.get('result_proxy'):
return proxify(url)
h = hmac.new(settings['server']['secret_key'], url.encode('utf-8'), hashlib.sha256).hexdigest()
h = new_hmac(settings['server']['secret_key'], url.encode('utf-8'))
return '{0}?{1}'.format(url_for('image_proxy'),
urlencode(dict(url=url.encode('utf-8'), h=h)))
@ -704,7 +705,7 @@ def image_proxy():
if not url:
return '', 400
h = hmac.new(settings['server']['secret_key'], url, hashlib.sha256).hexdigest()
h = new_hmac(settings['server']['secret_key'], url)
if h != request.args.get('h'):
return '', 400
@ -731,7 +732,7 @@ def image_proxy():
logger.debug('image-proxy: wrong content-type: {0}'.format(resp.headers.get('content-type')))
return '', 400
img = ''
img = b''
chunk_counter = 0
for chunk in resp.iter_content(1024 * 1024):
@ -792,7 +793,8 @@ def opensearch():
@app.route('/favicon.ico')
def favicon():
return send_from_directory(os.path.join(app.root_path,
'static/themes',
static_path,
'themes',
get_current_theme_name(),
'img'),
'favicon.png',

View File

@ -0,0 +1,91 @@
# -*- coding: utf-8 -*-
from collections import defaultdict
import mock
from searx.engines import base
from searx.testing import SearxTestCase
class TestBaseEngine(SearxTestCase):
def test_request(self):
query = 'test_query'
dicto = defaultdict(dict)
dicto['pageno'] = 1
params = base.request(query, dicto)
self.assertIn('url', params)
self.assertIn('base-search.net', params['url'])
def test_response(self):
self.assertRaises(AttributeError, base.response, None)
self.assertRaises(AttributeError, base.response, [])
self.assertRaises(AttributeError, base.response, '')
self.assertRaises(AttributeError, base.response, '[]')
response = mock.Mock(text='<response></response>')
self.assertEqual(base.response(response), [])
xml_mock = """<?xml version="1.0"?>
<response>
<lst name="responseHeader">
<int name="status">0</int>
<int name="QTime">1</int>
</lst>
<result name="response" numFound="1" start="0">
<doc>
<date name="dchdate">2000-01-01T01:01:01Z</date>
<str name="dcdocid">1</str>
<str name="dccontinent">cna</str>
<str name="dccountry">us</str>
<str name="dccollection">ftciteseerx</str>
<str name="dcprovider">CiteSeerX</str>
<str name="dctitle">Science and more</str>
<arr name="dccreator">
<str>Someone</str>
</arr>
<arr name="dcperson">
<str>Someone</str>
</arr>
<arr name="dcsubject">
<str>Science and more</str>
</arr>
<str name="dcdescription">Science, and even more.</str>
<arr name="dccontributor">
<str>The neighbour</str>
</arr>
<str name="dcdate">2001</str>
<int name="dcyear">2001</int>
<arr name="dctype">
<str>text</str>
</arr>
<arr name="dctypenorm">
<str>1</str>
</arr>
<arr name="dcformat">
<str>application/pdf</str>
</arr>
<arr name="dccontenttype">
<str>application/pdf</str>
</arr>
<arr name="dcidentifier">
<str>http://example.org/</str>
</arr>
<str name="dclink">http://example.org</str>
<str name="dcsource">http://example.org</str>
<arr name="dclanguage">
<str>en</str>
</arr>
<str name="dcrights">Under the example.org licence</str>
<int name="dcoa">1</int>
<arr name="dclang">
<str>eng</str>
</arr>
</doc>
</result>
</response>"""
response = mock.Mock(text=xml_mock.encode('utf-8'))
results = base.response(response)
self.assertEqual(type(results), list)
self.assertEqual(len(results), 1)
self.assertEqual(results[0]['title'], 'Science and more')
self.assertEqual(results[0]['content'], 'Science, and even more.')

View File

@ -8,10 +8,12 @@ from searx.testing import SearxTestCase
class TestBingImagesEngine(SearxTestCase):
def test_request(self):
bing_images.supported_languages = ['fr-FR', 'en-US']
query = 'test_query'
dicto = defaultdict(dict)
dicto['pageno'] = 1
dicto['language'] = 'fr_FR'
dicto['language'] = 'fr-FR'
dicto['safesearch'] = 1
dicto['time_range'] = ''
params = bing_images.request(query, dicto)
@ -19,12 +21,19 @@ class TestBingImagesEngine(SearxTestCase):
self.assertTrue(query in params['url'])
self.assertTrue('bing.com' in params['url'])
self.assertTrue('SRCHHPGUSR' in params['cookies'])
self.assertTrue('fr' in params['cookies']['SRCHHPGUSR'])
self.assertTrue('DEMOTE' in params['cookies']['SRCHHPGUSR'])
self.assertTrue('_EDGE_S' in params['cookies'])
self.assertTrue('fr-fr' in params['cookies']['_EDGE_S'])
dicto['language'] = 'fr'
params = bing_images.request(query, dicto)
self.assertTrue('_EDGE_S' in params['cookies'])
self.assertTrue('fr-fr' in params['cookies']['_EDGE_S'])
dicto['language'] = 'all'
params = bing_images.request(query, dicto)
self.assertIn('SRCHHPGUSR', params['cookies'])
self.assertIn('en', params['cookies']['SRCHHPGUSR'])
self.assertTrue('_EDGE_S' in params['cookies'])
self.assertTrue('en-us' in params['cookies']['_EDGE_S'])
def test_response(self):
self.assertRaises(AttributeError, bing_images.response, None)
@ -82,3 +91,28 @@ class TestBingImagesEngine(SearxTestCase):
self.assertEqual(results[0]['content'], '')
self.assertEqual(results[0]['thumbnail_src'], 'thumb_url')
self.assertEqual(results[0]['img_src'], 'img_url')
def test_fetch_supported_languages(self):
html = """
<div>
<div id="region-section-content">
<ul class="b_vList">
<li>
<a href="https://bing...&setmkt=de-DE&s...">Germany</a>
<a href="https://bing...&setmkt=nb-NO&s...">Norway</a>
</li>
</ul>
<ul class="b_vList">
<li>
<a href="https://bing...&setmkt=es-AR&s...">Argentina</a>
</li>
</ul>
</div>
</div>
"""
response = mock.Mock(text=html)
languages = list(bing_images._fetch_supported_languages(response))
self.assertEqual(len(languages), 3)
self.assertIn('de-DE', languages)
self.assertIn('no-NO', languages)
self.assertIn('es-AR', languages)

View File

@ -8,6 +8,8 @@ from searx.testing import SearxTestCase
class TestBingVideosEngine(SearxTestCase):
def test_request(self):
bing_videos.supported_languages = ['fr-FR', 'en-US']
query = 'test_query'
dicto = defaultdict(dict)
dicto['pageno'] = 1

View File

@ -1,71 +0,0 @@
from collections import defaultdict
import mock
from searx.engines import blekko_images
from searx.testing import SearxTestCase
class TestBlekkoImagesEngine(SearxTestCase):
def test_request(self):
query = 'test_query'
dicto = defaultdict(dict)
dicto['pageno'] = 0
dicto['safesearch'] = 1
params = blekko_images.request(query, dicto)
self.assertIn('url', params)
self.assertIn(query, params['url'])
self.assertIn('blekko.com', params['url'])
self.assertIn('page', params['url'])
dicto['pageno'] = 1
params = blekko_images.request(query, dicto)
self.assertNotIn('page', params['url'])
def test_response(self):
self.assertRaises(AttributeError, blekko_images.response, None)
self.assertRaises(AttributeError, blekko_images.response, [])
self.assertRaises(AttributeError, blekko_images.response, '')
self.assertRaises(AttributeError, blekko_images.response, '[]')
response = mock.Mock(text='[]')
self.assertEqual(blekko_images.response(response), [])
json = """
[
{
"c": 1,
"page_url": "http://result_url.html",
"title": "Photo title",
"tn_url": "http://ts1.mm.bing.net/th?id=HN.608050619474382748&pid=15.1",
"url": "http://result_image.jpg"
},
{
"c": 2,
"page_url": "http://companyorange.simpsite.nl/OSM",
"title": "OSM",
"tn_url": "http://ts2.mm.bing.net/th?id=HN.608048068264919461&pid=15.1",
"url": "http://simpsite.nl/userdata2/58985/Home/OSM.bmp"
},
{
"c": 3,
"page_url": "http://invincible.webklik.nl/page/osm",
"title": "OSM",
"tn_url": "http://ts1.mm.bing.net/th?id=HN.608024514657649476&pid=15.1",
"url": "http://www.webklik.nl/user_files/2009_09/65324/osm.gif"
},
{
"c": 4,
"page_url": "http://www.offshorenorway.no/event/companyDetail/id/12492",
"title": "Go to OSM Offshore AS homepage",
"tn_url": "http://ts2.mm.bing.net/th?id=HN.608054265899847285&pid=15.1",
"url": "http://www.offshorenorway.no/firmalogo/OSM-logo.png"
}
]
"""
response = mock.Mock(text=json)
results = blekko_images.response(response)
self.assertEqual(type(results), list)
self.assertEqual(len(results), 4)
self.assertEqual(results[0]['title'], 'Photo title')
self.assertEqual(results[0]['url'], 'http://result_url.html')
self.assertEqual(results[0]['img_src'], 'http://result_image.jpg')

View File

@ -40,9 +40,6 @@ class TestFarooEngine(SearxTestCase):
response = mock.Mock(text='{"data": []}')
self.assertEqual(faroo.response(response), [])
response = mock.Mock(text='{"data": []}', status_code=401)
self.assertRaises(Exception, faroo.response, response)
response = mock.Mock(text='{"data": []}', status_code=429)
self.assertRaises(Exception, faroo.response, response)
@ -98,14 +95,14 @@ class TestFarooEngine(SearxTestCase):
response = mock.Mock(text=json)
results = faroo.response(response)
self.assertEqual(type(results), list)
self.assertEqual(len(results), 4)
self.assertEqual(len(results), 3)
self.assertEqual(results[0]['title'], 'This is the title')
self.assertEqual(results[0]['url'], 'http://this.is.the.url/')
self.assertEqual(results[0]['content'], 'This is the content')
self.assertEqual(results[1]['title'], 'This is the title2')
self.assertEqual(results[1]['url'], 'http://this.is.the.url2/')
self.assertEqual(results[1]['content'], 'This is the content2')
self.assertEqual(results[3]['img_src'], 'http://upload.wikimedia.org/optimized.jpg')
self.assertEqual(results[2]['thumbnail'], 'http://upload.wikimedia.org/optimized.jpg')
json = """
{}

File diff suppressed because one or more lines are too long

View File

@ -13,38 +13,92 @@ class TestNyaaEngine(SearxTestCase):
params = nyaa.request(query, dic)
self.assertTrue('url' in params)
self.assertTrue(query in params['url'])
self.assertTrue('nyaa.se' in params['url'])
self.assertTrue('nyaa.si' in params['url'])
def test_response(self):
resp = mock.Mock(text='<html></html>')
self.assertEqual(nyaa.response(resp), [])
html = """
<table class="tlist">
<tbody>
<tr class="trusted tlistrow">
<td class="tlisticon">
<a href="//www.nyaa.se" title="English-translated Anime">
<img src="//files.nyaa.se" alt="English-translated Anime">
</a>
</td>
<td class="tlistname">
<a href="//www.nyaa.se/?page3">
Sample torrent title
</a>
</td>
<td class="tlistdownload">
<a href="//www.nyaa.se/?page_dl" title="Download">
<img src="//files.nyaa.se/www-dl.png" alt="DL">
</a>
</td>
<td class="tlistsize">10 MiB</td>
<td class="tlistsn">1</td>
<td class="tlistln">3</td>
<td class="tlistdn">666</td>
<td class="tlistmn">0</td>
</tr>
</tbody>
<table class="table table-bordered table-hover table-striped torrent-list">
<thead>
<tr>
<th class="hdr-category text-center" style="width:80px;">
<div>Category</div>
</th>
<th class="hdr-name" style="width:auto;">
<div>Name</div>
</th>
<th class="hdr-comments sorting text-center" title="Comments" style="width:50px;">
<a href="/?f=0&amp;c=0_0&amp;q=Death+Parade&amp;s=comments&amp;o=desc"></a>
<i class="fa fa-comments-o"></i>
</th>
<th class="hdr-link text-center" style="width:70px;">
<div>Link</div>
</th>
<th class="hdr-size sorting text-center" style="width:100px;">
<a href="/?f=0&amp;c=0_0&amp;q=Death+Parade&amp;s=size&amp;o=desc"></a>
<div>Size</div>
</th>
<th class="hdr-date sorting_desc text-center" title="In local time" style="width:140px;">
<a href="/?f=0&amp;c=0_0&amp;q=Death+Parade&amp;s=id&amp;o=asc"></a>
<div>Date</div>
</th>
<th class="hdr-seeders sorting text-center" title="Seeders" style="width:50px;">
<a href="/?f=0&amp;c=0_0&amp;q=Death+Parade&amp;s=seeders&amp;o=desc"></a>
<i class="fa fa-arrow-up" aria-hidden="true"></i>
</th>
<th class="hdr-leechers sorting text-center" title="Leechers" style="width:50px;">
<a href="/?f=0&amp;c=0_0&amp;q=Death+Parade&amp;s=leechers&amp;o=desc"></a>
<i class="fa fa-arrow-down" aria-hidden="true"></i>
</th>
<th class="hdr-downloads sorting text-center" title="Completed downloads" style="width:50px;">
<a href="/?f=0&amp;c=0_0&amp;q=Death+Parade&amp;s=downloads&amp;o=desc"></a>
<i class="fa fa-check" aria-hidden="true"></i>
</th>
</tr>
</thead>
<tbody>
<tr class="default">
<td style="padding:0 4px;">
<a href="/?c=1_2" title="Anime - English-translated">
<img src="/static/img/icons/nyaa/1_2.png" alt="Anime - English-translated">
</a>
</td>
<td colspan="2">
<a href="/view/1" title="Sample title 1">Sample title 1</a>
</td>
<td class="text-center" style="white-space: nowrap;">
<a href="/download/1.torrent"><i class="fa fa-fw fa-download"></i></a>
<a href="magnet:?xt=urn:btih:2"><i class="fa fa-fw fa-magnet"></i></a>
</td>
<td class="text-center">723.7 MiB</td>
<td class="text-center" data-timestamp="1503307456" title="1 week 3
days 9 hours 44 minutes 39 seconds ago">2017-08-21 11:24</td>
<td class="text-center" style="color: green;">1</td>
<td class="text-center" style="color: red;">3</td>
<td class="text-center">12</td>
</tr>
<tr class="default">
<td style="padding:0 4px;">
<a href="/?c=1_2" title="Anime - English-translated">
<img src="/static/img/icons/nyaa/1_2.png" alt="Anime - English-translated">
</a>
</td>
<td colspan="2">
<a href="/view/2" title="Sample title 2">Sample title 2</a>
</td>
<td class="text-center" style="white-space: nowrap;">
<a href="magnet:?xt=urn:btih:2"><i class="fa fa-fw fa-magnet"></i></a>
</td>
<td class="text-center">8.2 GiB</td>
<td class="text-center" data-timestamp="1491608400" title="4 months 3
weeks 4 days 19 hours 28 minutes 55 seconds ago">2017-04-08 01:40</td>
<td class="text-center" style="color: green;">10</td>
<td class="text-center" style="color: red;">1</td>
<td class="text-center">206</td>
</tr>
</tbody>
</table>
"""
@ -52,15 +106,19 @@ class TestNyaaEngine(SearxTestCase):
results = nyaa.response(resp)
self.assertEqual(type(results), list)
self.assertEqual(len(results), 1)
self.assertEqual(len(results), 2)
r = results[0]
self.assertTrue(r['url'].find('www.nyaa.se/?page3') >= 0)
self.assertTrue(r['torrentfile'].find('www.nyaa.se/?page_dl') >= 0)
self.assertTrue(r['content'].find('English-translated Anime') >= 0)
self.assertTrue(r['content'].find('Downloaded 666 times.') >= 0)
self.assertTrue(r['url'].find('1') >= 0)
self.assertTrue(r['torrentfile'].find('1.torrent') >= 0)
self.assertTrue(r['content'].find('Anime - English-translated') >= 0)
self.assertTrue(r['content'].find('Downloaded 12 times.') >= 0)
self.assertEqual(r['title'], 'Sample torrent title')
self.assertEqual(r['title'], 'Sample title 1')
self.assertEqual(r['seed'], 1)
self.assertEqual(r['leech'], 3)
self.assertEqual(r['filesize'], 10 * 1024 * 1024)
self.assertEqual(r['filesize'], 723700000)
r = results[1]
self.assertTrue(r['url'].find('2') >= 0)
self.assertTrue(r['magnetlink'].find('magnet:') >= 0)

View File

@ -139,9 +139,9 @@ class TestSwisscowsEngine(SearxTestCase):
<div id="regions-popup">
<div>
<ul>
<li><a data-val="browser"></a></li>
<li><a data-val="de-CH"></a></li>
<li><a data-val="fr-CH"></a></li>
<li><a data-search-language="browser"></a></li>
<li><a data-search-language="de-CH"></a></li>
<li><a data-search-language="fr-CH"></a></li>
</ul>
</div>
</div>

View File

@ -14,7 +14,7 @@ class TestTorrentzEngine(SearxTestCase):
params = torrentz.request(query, dic)
self.assertTrue('url' in params)
self.assertTrue(query in params['url'])
self.assertTrue('torrentz.eu' in params['url'])
self.assertTrue('torrentz2.eu' in params['url'])
def test_response(self):
resp = mock.Mock(text='<html></html>')
@ -30,13 +30,11 @@ class TestTorrentzEngine(SearxTestCase):
books ebooks
</dt>
<dd>
<span class="v">1</span>
<span class="a">
<span title="Sun, 22 Nov 2015 03:01:42">4 months</span>
</span>
<span class="s">30 MB</span>
<span class="u">14</span>
<span class="d">1</span>
<span>1</span>
<span title="1503595924">5 hours</span>
<span>30 MB</span>
<span>14</span>
<span>1</span>
</dd>
</dl>
@ -48,13 +46,11 @@ class TestTorrentzEngine(SearxTestCase):
books ebooks
</dt>
<dd>
<span class="v">1</span>
<span class="a">
<span title="Sun, 2124091j0j190gm42">4 months</span>
</span>
<span class="s">30MB</span>
<span class="u">5,555</span>
<span class="d">1,234,567</span>
<span>1</span>
<span title="1503595924 aaa">5 hours</span>
<span>30MB</span>
<span>5,555</span>
<span>1,234,567</span>
</dd>
</dl>
</div>
@ -68,10 +64,10 @@ class TestTorrentzEngine(SearxTestCase):
# testing against the first result
r = results[0]
self.assertEqual(r['url'], 'https://torrentz.eu/4362e08b1d80e1820fb2550b752f9f3126fe76d6')
self.assertEqual(r['url'], 'https://torrentz2.eu/4362e08b1d80e1820fb2550b752f9f3126fe76d6')
self.assertEqual(r['title'], 'Completely valid info books ebooks')
# 22 Nov 2015 03:01:42
self.assertEqual(r['publishedDate'], datetime(2015, 11, 22, 3, 1, 42))
self.assertEqual(r['publishedDate'], datetime.fromtimestamp(1503595924))
self.assertEqual(r['seed'], 14)
self.assertEqual(r['leech'], 1)
self.assertEqual(r['filesize'], 30 * 1024 * 1024)
@ -79,7 +75,7 @@ class TestTorrentzEngine(SearxTestCase):
# testing against the second result
r = results[1]
self.assertEqual(r['url'], 'https://torrentz.eu/poaskdpokaspod')
self.assertEqual(r['url'], 'https://torrentz2.eu/poaskdpokaspod')
self.assertEqual(r['title'], 'Invalid hash and date and filesize books ebooks')
self.assertEqual(r['seed'], 5555)
self.assertEqual(r['leech'], 1234567)

View File

@ -8,13 +8,13 @@
# are written in current directory to avoid overwriting in case something goes wrong.
from requests import get
from urllib import urlencode
from lxml.html import fromstring
from json import loads, dumps
from json import loads, dump
import io
from sys import path
path.append('../searx') # noqa
from searx import settings
from searx.url_utils import urlencode
from searx.engines import initialize_engines, engines
# Geonames API for country names.
@ -70,7 +70,7 @@ def get_country_name(locale):
json = loads(response.text)
content = json.get('geonames', None)
if content is None or len(content) != 1:
print "No country name found for " + locale[0] + "-" + locale[1]
print("No country name found for " + locale[0] + "-" + locale[1])
return ''
return content[0].get('countryName', '')
@ -84,11 +84,11 @@ def fetch_supported_languages():
try:
engines_languages[engine_name] = engines[engine_name].fetch_supported_languages()
except Exception as e:
print e
print(e)
# write json file
with io.open(engines_languages_file, "w", encoding="utf-8") as f:
f.write(unicode(dumps(engines_languages, ensure_ascii=False, encoding="utf-8")))
dump(engines_languages, f, ensure_ascii=False)
# Join all language lists.
@ -97,7 +97,7 @@ def join_language_lists():
global languages
# include wikipedia first for more accurate language names
languages = {code: lang for code, lang
in engines_languages['wikipedia'].iteritems()
in engines_languages['wikipedia'].items()
if valid_code(code)}
for engine_name in engines_languages:
@ -121,7 +121,7 @@ def join_language_lists():
# filter list to include only languages supported by most engines
min_supported_engines = int(0.70 * len(engines_languages))
languages = {code: lang for code, lang
in languages.iteritems()
in languages.items()
if len(lang.get('counter', [])) >= min_supported_engines or
len(languages.get(code.split('-')[0], {}).get('counter', [])) >= min_supported_engines}
@ -165,7 +165,7 @@ def filter_single_country_languages():
# Write languages.py.
def write_languages_file():
new_file = open(languages_file, 'w')
new_file = open(languages_file, 'wb')
file_content = '# -*- coding: utf-8 -*-\n'\
+ '# list of language codes\n'\
+ '# this file is generated automatically by utils/update_search_languages.py\n'\

View File

@ -7,9 +7,9 @@
SEARX_DIR='searx'
pybabel extract -F babel.cfg -o messages.pot $SEARX_DIR
for f in `ls $SEARX_DIR'/translations/'`; do
pybabel update -N -i messages.pot -d $SEARX_DIR'/translations/' -l $f
pybabel extract -F babel.cfg -o messages.pot "$SEARX_DIR"
for f in `ls "$SEARX_DIR"'/translations/'`; do
pybabel update -N -i messages.pot -d "$SEARX_DIR"'/translations/' -l "$f"
done
echo '[!] update done, edit .po files if required and run pybabel compile -d searx/translations/'