Browse Source

Merge pull request #1 from asciimoo/master

-
Apply55gx 7 years ago
parent
commit
d800e3fcfa
49 changed files with 754 additions and 1473 deletions
  1. 31
    0
      .codecov.yml
  2. 3
    3
      .travis.yml
  3. 9
    3
      README.rst
  4. 37
    37
      manage.sh
  5. 1
    0
      requirements-dev.txt
  6. 1
    1
      requirements.txt
  7. 1
    1
      searx/data/engines_languages.json
  8. 47
    9
      searx/engines/bing_images.py
  9. 4
    1
      searx/engines/bing_videos.py
  10. 0
    70
      searx/engines/blekko_images.py
  11. 7
    0
      searx/engines/digg.py
  12. 1
    1
      searx/engines/duckduckgo.py
  13. 19
    39
      searx/engines/faroo.py
  14. 0
    62
      searx/engines/generalfile.py
  15. 6
    2
      searx/engines/gigablast.py
  16. 2
    2
      searx/engines/google_news.py
  17. 40
    49
      searx/engines/nyaa.py
  18. 1
    1
      searx/engines/swisscows.py
  19. 2
    3
      searx/engines/tokyotoshokan.py
  20. 22
    16
      searx/engines/torrentz.py
  21. 8
    10
      searx/languages.py
  22. 28
    28
      searx/settings.yml
  23. 1
    8
      searx/static/themes/oscar/css/logicodev.min.css
  24. 1
    1
      searx/static/themes/oscar/css/pointhi.min.css
  25. 1
    1
      searx/static/themes/oscar/js/searx.min.js
  26. 2
    0
      searx/static/themes/oscar/less/logicodev/oscar.less
  27. 3
    0
      searx/static/themes/oscar/less/logicodev/preferences.less
  28. 2
    0
      searx/static/themes/oscar/less/pointhi/oscar.less
  29. 3
    0
      searx/static/themes/oscar/less/pointhi/preferences.less
  30. 11
    11
      searx/templates/courgette/result_templates/code.html
  31. 11
    11
      searx/templates/legacy/result_templates/code.html
  32. 99
    88
      searx/templates/oscar/macros.html
  33. 17
    14
      searx/templates/oscar/preferences.html
  34. 1
    2
      searx/templates/simple/macros.html
  35. BIN
      searx/translations/de_DE/LC_MESSAGES/messages.mo
  36. 0
    844
      searx/translations/de_DE/LC_MESSAGES/messages.po
  37. 18
    0
      searx/utils.py
  38. 6
    4
      searx/webapp.py
  39. 91
    0
      tests/unit/engines/test_base.py
  40. 38
    4
      tests/unit/engines/test_bing_images.py
  41. 2
    0
      tests/unit/engines/test_bing_videos.py
  42. 0
    71
      tests/unit/engines/test_blekko_images.py
  43. 2
    5
      tests/unit/engines/test_faroo.py
  44. 56
    6
      tests/unit/engines/test_google_news.py
  45. 91
    33
      tests/unit/engines/test_nyaa.py
  46. 3
    3
      tests/unit/engines/test_swisscows.py
  47. 14
    18
      tests/unit/engines/test_torrentz.py
  48. 8
    8
      utils/fetch_languages.py
  49. 3
    3
      utils/update-translations.sh

+ 31
- 0
.codecov.yml View File

@@ -0,0 +1,31 @@
1
+comment: false
2
+coverage:
3
+  status:
4
+    project:
5
+      default:
6
+        # basic
7
+        target: auto
8
+        threshold: null
9
+        base: auto 
10
+        # advanced
11
+        branches: null
12
+        if_no_uploads: error
13
+        if_not_found: success
14
+        if_ci_failed: error
15
+        only_pulls: false
16
+        flags: null
17
+        paths: null
18
+    patch:
19
+      default:
20
+        # basic
21
+        target: auto
22
+        threshold: null
23
+        base: auto 
24
+        # advanced
25
+        branches: null
26
+        if_no_uploads: error
27
+        if_not_found: success
28
+        if_ci_failed: error
29
+        only_pulls: false
30
+        flags: null
31
+        paths: null

+ 3
- 3
.travis.yml View File

@@ -13,21 +13,21 @@ python:
13 13
 before_install:
14 14
   - "export DISPLAY=:99.0"
15 15
   - "sh -e /etc/init.d/xvfb start"
16
-  - npm install less less-plugin-clean-css grunt-cli
16
+  - npm install less@2.7 less-plugin-clean-css grunt-cli
17 17
   - export PATH=`pwd`/node_modules/.bin:$PATH
18 18
   - ./manage.sh install_geckodriver ~/drivers
19 19
   - export PATH=~/drivers:$PATH
20 20
 install:
21 21
   - ./manage.sh npm_packages
22 22
   - ./manage.sh update_dev_packages
23
-  - pip install coveralls
23
+  - pip install codecov
24 24
 script:
25 25
   - ./manage.sh styles
26 26
   - ./manage.sh grunt_build
27 27
   - ./manage.sh tests
28 28
 after_success:
29 29
   - ./manage.sh py_test_coverage
30
-  - coveralls
30
+  - codecov
31 31
 notifications:
32 32
   irc:
33 33
     channels:

+ 9
- 3
README.rst View File

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

+ 37
- 37
manage.sh View File

@@ -1,11 +1,11 @@
1 1
 #!/bin/sh
2 2
 
3
-BASE_DIR=$(dirname "`readlink -f "$0"`")
4
-PYTHONPATH=$BASE_DIR
3
+BASE_DIR="$(dirname -- "`readlink -f -- "$0"`")"
4
+PYTHONPATH="$BASE_DIR"
5 5
 SEARX_DIR="$BASE_DIR/searx"
6
-ACTION=$1
6
+ACTION="$1"
7 7
 
8
-cd "$BASE_DIR"
8
+cd -- "$BASE_DIR"
9 9
 
10 10
 update_packages() {
11 11
     pip install --upgrade pip
@@ -22,40 +22,40 @@ install_geckodriver() {
22 22
     echo '[!] Checking geckodriver'
23 23
     # TODO : check the current geckodriver version
24 24
     set -e
25
-    geckodriver -V 2>1 > /dev/null || NOTFOUND=1
25
+    geckodriver -V > /dev/null 2>&1 || NOTFOUND=1
26 26
     set +e
27
-    if [ -z $NOTFOUND ]; then
28
-	return
27
+    if [ -z "$NOTFOUND" ]; then
28
+        return
29 29
     fi
30 30
     GECKODRIVER_VERSION="v0.18.0"
31
-    PLATFORM=`python -c "import six; import platform; six.print_(platform.system().lower(), platform.architecture()[0])"`
32
-    case $PLATFORM in
33
-	"linux 32bit" | "linux2 32bit") ARCH="linux32";;
34
-	"linux 64bit" | "linux2 64bit") ARCH="linux64";;
35
-	"windows 32 bit") ARCH="win32";;
36
-	"windows 64 bit") ARCH="win64";;
37
-	"mac 64bit") ARCH="macos";;
31
+    PLATFORM="`python -c "import six; import platform; six.print_(platform.system().lower(), platform.architecture()[0])"`"
32
+    case "$PLATFORM" in
33
+        "linux 32bit" | "linux2 32bit") ARCH="linux32";;
34
+        "linux 64bit" | "linux2 64bit") ARCH="linux64";;
35
+        "windows 32 bit") ARCH="win32";;
36
+        "windows 64 bit") ARCH="win64";;
37
+        "mac 64bit") ARCH="macos";;
38 38
     esac
39 39
     GECKODRIVER_URL="https://github.com/mozilla/geckodriver/releases/download/$GECKODRIVER_VERSION/geckodriver-$GECKODRIVER_VERSION-$ARCH.tar.gz";
40 40
 
41 41
     if [ -z "$1" ]; then
42
-	if [ -z "$VIRTUAL_ENV" ]; then
43
-	    echo "geckodriver can't be installed because VIRTUAL_ENV is not set, you should download it from\n  $GECKODRIVER_URL"
44
-	    exit    
45
-	else
46
-	    GECKODRIVER_DIR="$VIRTUAL_ENV/bin"
47
-	fi
42
+        if [ -z "$VIRTUAL_ENV" ]; then
43
+            echo "geckodriver can't be installed because VIRTUAL_ENV is not set, you should download it from\n  $GECKODRIVER_URL"
44
+            exit
45
+        else
46
+            GECKODRIVER_DIR="$VIRTUAL_ENV/bin"
47
+        fi
48 48
     else
49
-	GECKODRIVER_DIR="$1"
50
-	mkdir -p "$GECKODRIVER_DIR"
49
+        GECKODRIVER_DIR="$1"
50
+        mkdir -p -- "$GECKODRIVER_DIR"
51 51
     fi
52 52
 
53 53
     echo "Installing $GECKODRIVER_DIR/geckodriver from\n  $GECKODRIVER_URL"
54
-    
55
-    FILE=`mktemp`
56
-    wget "$GECKODRIVER_URL" -qO $FILE && tar xz -C "$GECKODRIVER_DIR" -f $FILE geckodriver
57
-    rm $FILE
58
-    chmod 777 "$GECKODRIVER_DIR/geckodriver"
54
+
55
+    FILE="`mktemp`"
56
+    wget -qO "$FILE" -- "$GECKODRIVER_URL" && tar xz -C "$GECKODRIVER_DIR" -f "$FILE" geckodriver
57
+    rm -- "$FILE"
58
+    chmod 777 -- "$GECKODRIVER_DIR/geckodriver"
59 59
 }
60 60
 
61 61
 pep8_check() {
@@ -73,14 +73,14 @@ unit_tests() {
73 73
 
74 74
 py_test_coverage() {
75 75
     echo '[!] Running python test coverage'
76
-    PYTHONPATH=`pwd` python -m nose2 -C --coverage "$SEARX_DIR" -s "$BASE_DIR/tests/unit"
77
-    coverage report
78
-    coverage html
76
+    PYTHONPATH="`pwd`" python -m nose2 -C --log-capture --with-coverage --coverage "$SEARX_DIR" -s "$BASE_DIR/tests/unit" \
77
+    && coverage report \
78
+    && coverage html
79 79
 }
80 80
 
81 81
 robot_tests() {
82 82
     echo '[!] Running robot tests'
83
-    PYTHONPATH=`pwd` python "$SEARX_DIR/testing.py" robot
83
+    PYTHONPATH="`pwd`" python "$SEARX_DIR/testing.py" robot
84 84
 }
85 85
 
86 86
 tests() {
@@ -113,18 +113,18 @@ styles() {
113 113
 
114 114
 npm_packages() {
115 115
     echo '[!] install NPM packages for oscar theme'
116
-    cd $BASE_DIR/searx/static/themes/oscar
116
+    cd -- "$BASE_DIR/searx/static/themes/oscar"
117 117
     npm install
118 118
 
119
-    echo '[!] install NPM packages for simple theme'    
120
-    cd $BASE_DIR/searx/static/themes/simple
119
+    echo '[!] install NPM packages for simple theme'
120
+    cd -- "$BASE_DIR/searx/static/themes/simple"
121 121
     npm install
122 122
 }
123 123
 
124 124
 grunt_build() {
125 125
     echo '[!] Grunt build : oscar theme'
126 126
     grunt --gruntfile "$SEARX_DIR/static/themes/oscar/gruntfile.js"
127
-    echo '[!] Grunt build : simple theme'    
127
+    echo '[!] Grunt build : simple theme'
128 128
     grunt --gruntfile "$SEARX_DIR/static/themes/simple/gruntfile.js"
129 129
 }
130 130
 
@@ -133,7 +133,7 @@ locales() {
133 133
 }
134 134
 
135 135
 help() {
136
-    [ -z "$1" ] || printf "Error: $1\n"
136
+    [ -z "$1" ] || printf 'Error: %s\n' "$1"
137 137
     echo "Searx manage.sh help
138 138
 
139 139
 Commands
@@ -156,4 +156,4 @@ Commands
156 156
 
157 157
 [ "$(command -V "$ACTION" | grep ' function$')" = "" ] \
158 158
     && help "action not found" \
159
-    || $ACTION "$2"
159
+    || "$ACTION" "$2"

+ 1
- 0
requirements-dev.txt View File

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

+ 1
- 1
requirements.txt View File

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

+ 1
- 1
searx/data/engines_languages.json
File diff suppressed because it is too large
View File


+ 47
- 9
searx/engines/bing_images.py View File

@@ -18,7 +18,6 @@
18 18
 from lxml import html
19 19
 from json import loads
20 20
 import re
21
-from searx.engines.bing import _fetch_supported_languages, supported_languages_url
22 21
 from searx.url_utils import urlencode
23 22
 
24 23
 # engine dependent config
@@ -26,6 +25,8 @@ categories = ['images']
26 25
 paging = True
27 26
 safesearch = True
28 27
 time_range_support = True
28
+language_support = True
29
+supported_languages_url = 'https://www.bing.com/account/general'
29 30
 
30 31
 # search-url
31 32
 base_url = 'https://www.bing.com/'
@@ -45,23 +46,41 @@ safesearch_types = {2: 'STRICT',
45 46
 _quote_keys_regex = re.compile('({|,)([a-z][a-z0-9]*):(")', re.I | re.U)
46 47
 
47 48
 
49
+# get supported region code
50
+def get_region_code(lang, lang_list=None):
51
+    region = None
52
+    if lang in (lang_list or supported_languages):
53
+        region = lang
54
+    elif lang.startswith('no'):
55
+        region = 'nb-NO'
56
+    else:
57
+        # try to get a supported country code with language
58
+        lang = lang.split('-')[0]
59
+        for lc in (lang_list or supported_languages):
60
+            if lang == lc.split('-')[0]:
61
+                region = lc
62
+                break
63
+    if region:
64
+        return region.lower()
65
+    else:
66
+        return 'en-us'
67
+
68
+
48 69
 # do search-request
49 70
 def request(query, params):
50 71
     offset = (params['pageno'] - 1) * 10 + 1
51 72
 
52
-    # required for cookie
53
-    if params['language'] == 'all':
54
-        language = 'en-US'
55
-    else:
56
-        language = params['language']
57
-
58 73
     search_path = search_string.format(
59 74
         query=urlencode({'q': query}),
60 75
         offset=offset)
61 76
 
77
+    language = get_region_code(params['language'])
78
+
62 79
     params['cookies']['SRCHHPGUSR'] = \
63
-        'NEWWND=0&NRSLT=-1&SRCHLANG=' + language.split('-')[0] +\
64
-        '&ADLT=' + safesearch_types.get(params['safesearch'], 'DEMOTE')
80
+        'ADLT=' + safesearch_types.get(params['safesearch'], 'DEMOTE')
81
+
82
+    params['cookies']['_EDGE_S'] = 'mkt=' + language +\
83
+        '&ui=' + language + '&F=1'
65 84
 
66 85
     params['url'] = base_url + search_path
67 86
     if params['time_range'] in time_range_dict:
@@ -106,3 +125,22 @@ def response(resp):
106 125
 
107 126
     # return results
108 127
     return results
128
+
129
+
130
+# get supported languages from their site
131
+def _fetch_supported_languages(resp):
132
+    supported_languages = []
133
+    dom = html.fromstring(resp.text)
134
+
135
+    regions_xpath = '//div[@id="region-section-content"]' \
136
+                    + '//ul[@class="b_vList"]/li/a/@href'
137
+
138
+    regions = dom.xpath(regions_xpath)
139
+    for region in regions:
140
+        code = re.search('setmkt=[^\&]+', region).group()[7:]
141
+        if code == 'nb-NO':
142
+            code = 'no-NO'
143
+
144
+        supported_languages.append(code)
145
+
146
+    return supported_languages

+ 4
- 1
searx/engines/bing_videos.py View File

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

+ 0
- 70
searx/engines/blekko_images.py View File

@@ -1,70 +0,0 @@
1
-"""
2
- Blekko (Images)
3
-
4
- @website     https://blekko.com
5
- @provide-api yes (inofficial)
6
-
7
- @using-api   yes
8
- @results     JSON
9
- @stable      yes
10
- @parse       url, title, img_src
11
-"""
12
-
13
-from json import loads
14
-from searx.url_utils import urlencode
15
-
16
-# engine dependent config
17
-categories = ['images']
18
-paging = True
19
-safesearch = True
20
-
21
-# search-url
22
-base_url = 'https://blekko.com'
23
-search_url = '/api/images?{query}&c={c}'
24
-
25
-# safesearch definitions
26
-safesearch_types = {2: '1',
27
-                    1: '',
28
-                    0: '0'}
29
-
30
-
31
-# do search-request
32
-def request(query, params):
33
-    c = (params['pageno'] - 1) * 48
34
-
35
-    params['url'] = base_url +\
36
-        search_url.format(query=urlencode({'q': query}),
37
-                          c=c)
38
-
39
-    if params['pageno'] != 1:
40
-        params['url'] += '&page={pageno}'.format(pageno=(params['pageno'] - 1))
41
-
42
-    # let Blekko know we wan't have profiling
43
-    params['cookies']['tag_lesslogging'] = '1'
44
-
45
-    # parse safesearch argument
46
-    params['cookies']['safesearch'] = safesearch_types.get(params['safesearch'], '')
47
-
48
-    return params
49
-
50
-
51
-# get response from search-request
52
-def response(resp):
53
-    results = []
54
-
55
-    search_results = loads(resp.text)
56
-
57
-    # return empty array if there are no results
58
-    if not search_results:
59
-        return []
60
-
61
-    for result in search_results:
62
-        # append result
63
-        results.append({'url': result['page_url'],
64
-                        'title': result['title'],
65
-                        'content': '',
66
-                        'img_src': result['url'],
67
-                        'template': 'images.html'})
68
-
69
-    # return results
70
-    return results

+ 7
- 0
searx/engines/digg.py View File

@@ -10,6 +10,8 @@
10 10
  @parse       url, title, content, publishedDate, thumbnail
11 11
 """
12 12
 
13
+import random
14
+import string
13 15
 from dateutil import parser
14 16
 from json import loads
15 17
 from lxml import html
@@ -30,12 +32,17 @@ title_xpath = './/h2//a//text()'
30 32
 content_xpath = './/p//text()'
31 33
 pubdate_xpath = './/time'
32 34
 
35
+digg_cookie_chars = string.ascii_uppercase + string.ascii_lowercase +\
36
+    string.digits + "+_"
37
+
33 38
 
34 39
 # do search-request
35 40
 def request(query, params):
36 41
     offset = (params['pageno'] - 1) * 10
37 42
     params['url'] = search_url.format(position=offset,
38 43
                                       query=quote_plus(query))
44
+    params['cookies']['frontend.auid'] = ''.join(random.choice(
45
+        digg_cookie_chars) for _ in range(22))
39 46
     return params
40 47
 
41 48
 

+ 1
- 1
searx/engines/duckduckgo.py View File

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

+ 19
- 39
searx/engines/faroo.py View File

@@ -4,7 +4,7 @@
4 4
  @website     http://www.faroo.com
5 5
  @provide-api yes (http://www.faroo.com/hp/api/api.html), require API-key
6 6
 
7
- @using-api   yes
7
+ @using-api   no
8 8
  @results     JSON
9 9
  @stable      yes
10 10
  @parse       url, title, content, publishedDate, img_src
@@ -20,18 +20,16 @@ categories = ['general', 'news']
20 20
 paging = True
21 21
 language_support = True
22 22
 number_of_results = 10
23
-api_key = None
24 23
 
25 24
 # search-url
26 25
 url = 'http://www.faroo.com/'
27
-search_url = url + 'api?{query}'\
28
-                      '&start={offset}'\
29
-                      '&length={number_of_results}'\
30
-                      '&l={language}'\
31
-                      '&src={categorie}'\
32
-                      '&i=false'\
33
-                      '&f=json'\
34
-                      '&key={api_key}'  # noqa
26
+search_url = url + 'instant.json?{query}'\
27
+    '&start={offset}'\
28
+    '&length={number_of_results}'\
29
+    '&l={language}'\
30
+    '&src={categorie}'\
31
+    '&i=false'\
32
+    '&c=false'
35 33
 
36 34
 search_category = {'general': 'web',
37 35
                    'news': 'news'}
@@ -57,21 +55,15 @@ def request(query, params):
57 55
                                       number_of_results=number_of_results,
58 56
                                       query=urlencode({'q': query}),
59 57
                                       language=language,
60
-                                      categorie=categorie,
61
-                                      api_key=api_key)
58
+                                      categorie=categorie)
62 59
 
63
-    # using searx User-Agent
64
-    params['headers']['User-Agent'] = searx_useragent()
60
+    params['headers']['Referer'] = url
65 61
 
66 62
     return params
67 63
 
68 64
 
69 65
 # get response from search-request
70 66
 def response(resp):
71
-    # HTTP-Code 401: api-key is not valide
72
-    if resp.status_code == 401:
73
-        raise Exception("API key is not valide")
74
-
75 67
     # HTTP-Code 429: rate limit exceeded
76 68
     if resp.status_code == 429:
77 69
         raise Exception("rate limit has been exceeded!")
@@ -86,31 +78,19 @@ def response(resp):
86 78
 
87 79
     # parse results
88 80
     for result in search_res['results']:
81
+        publishedDate = None
82
+        result_json = {'url': result['url'], 'title': result['title'],
83
+                       'content': result['kwic']}
89 84
         if result['news']:
90
-            # timestamp (milliseconds since 1970)
91
-            publishedDate = datetime.datetime.fromtimestamp(result['date'] / 1000.0)  # noqa
92
-
93
-            # append news result
94
-            results.append({'url': result['url'],
95
-                            'title': result['title'],
96
-                            'publishedDate': publishedDate,
97
-                            'content': result['kwic']})
98
-
99
-        else:
100
-            # append general result
101
-            # TODO, publishedDate correct?
102
-            results.append({'url': result['url'],
103
-                            'title': result['title'],
104
-                            'content': result['kwic']})
85
+            result_json['publishedDate'] = \
86
+                datetime.datetime.fromtimestamp(result['date'] / 1000.0)
105 87
 
106 88
         # append image result if image url is set
107
-        # TODO, show results with an image like in faroo
108 89
         if result['iurl']:
109
-            results.append({'template': 'images.html',
110
-                            'url': result['url'],
111
-                            'title': result['title'],
112
-                            'content': result['kwic'],
113
-                            'img_src': result['iurl']})
90
+            result_json['template'] = 'videos.html'
91
+            result_json['thumbnail'] = result['iurl']
92
+
93
+        results.append(result_json)
114 94
 
115 95
     # return results
116 96
     return results

+ 0
- 62
searx/engines/generalfile.py View File

@@ -1,62 +0,0 @@
1
-"""
2
- General Files (Files)
3
-
4
- @website     http://www.general-files.org
5
- @provide-api no (nothing found)
6
-
7
- @using-api   no (because nothing found)
8
- @results     HTML (using search portal)
9
- @stable      no (HTML can change)
10
- @parse       url, title, content
11
-
12
- @todo        detect torrents?
13
-"""
14
-
15
-from lxml import html
16
-
17
-# engine dependent config
18
-categories = ['files']
19
-paging = True
20
-
21
-# search-url
22
-base_url = 'http://www.general-file.com'
23
-search_url = base_url + '/files-{letter}/{query}/{pageno}'
24
-
25
-# specific xpath variables
26
-result_xpath = '//table[@class="block-file"]'
27
-title_xpath = './/h2/a//text()'
28
-url_xpath = './/h2/a/@href'
29
-content_xpath = './/p//text()'
30
-
31
-
32
-# do search-request
33
-def request(query, params):
34
-
35
-    params['url'] = search_url.format(query=query,
36
-                                      letter=query[0],
37
-                                      pageno=params['pageno'])
38
-
39
-    return params
40
-
41
-
42
-# get response from search-request
43
-def response(resp):
44
-    results = []
45
-
46
-    dom = html.fromstring(resp.text)
47
-
48
-    # parse results
49
-    for result in dom.xpath(result_xpath):
50
-        url = result.xpath(url_xpath)[0]
51
-
52
-        # skip fast download links
53
-        if not url.startswith('/'):
54
-            continue
55
-
56
-        # append result
57
-        results.append({'url': base_url + url,
58
-                        'title': ''.join(result.xpath(title_xpath)),
59
-                        'content': ''.join(result.xpath(content_xpath))})
60
-
61
-    # return results
62
-    return results

+ 6
- 2
searx/engines/gigablast.py View File

@@ -10,6 +10,7 @@
10 10
  @parse       url, title, content
11 11
 """
12 12
 
13
+import random
13 14
 from json import loads
14 15
 from time import time
15 16
 from lxml.html import fromstring
@@ -32,7 +33,8 @@ search_string = 'search?{query}'\
32 33
     '&qh=0'\
33 34
     '&qlang={lang}'\
34 35
     '&ff={safesearch}'\
35
-    '&rxikd={rxikd}'  # random number - 9 digits
36
+    '&rxieu={rxieu}'\
37
+    '&rand={rxikd}'  # current unix timestamp
36 38
 
37 39
 # specific xpath variables
38 40
 results_xpath = '//response//result'
@@ -59,10 +61,12 @@ def request(query, params):
59 61
     else:
60 62
         safesearch = 0
61 63
 
64
+    # rxieu is some kind of hash from the search query, but accepts random atm
62 65
     search_path = search_string.format(query=urlencode({'q': query}),
63 66
                                        offset=offset,
64 67
                                        number_of_results=number_of_results,
65
-                                       rxikd=str(time())[:9],
68
+                                       rxikd=int(time() * 1000),
69
+                                       rxieu=random.randint(1000000000, 9999999999),
66 70
                                        lang=language,
67 71
                                        safesearch=safesearch)
68 72
 

+ 2
- 2
searx/engines/google_news.py View File

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

+ 40
- 49
searx/engines/nyaa.py View File

@@ -1,7 +1,7 @@
1 1
 """
2
- Nyaa.se (Anime Bittorrent tracker)
2
+ Nyaa.si (Anime Bittorrent tracker)
3 3
 
4
- @website      http://www.nyaa.se/
4
+ @website      http://www.nyaa.si/
5 5
  @provide-api  no
6 6
  @using-api    no
7 7
  @results      HTML
@@ -12,50 +12,25 @@
12 12
 from lxml import html
13 13
 from searx.engines.xpath import extract_text
14 14
 from searx.url_utils import urlencode
15
+from searx.utils import get_torrent_size, int_or_zero
15 16
 
16 17
 # engine dependent config
17 18
 categories = ['files', 'images', 'videos', 'music']
18 19
 paging = True
19 20
 
20 21
 # search-url
21
-base_url = 'http://www.nyaa.se/'
22
+base_url = 'http://www.nyaa.si/'
22 23
 search_url = base_url + '?page=search&{query}&offset={offset}'
23 24
 
24 25
 # xpath queries
25
-xpath_results = '//table[@class="tlist"]//tr[contains(@class, "tlistrow")]'
26
-xpath_category = './/td[@class="tlisticon"]/a'
27
-xpath_title = './/td[@class="tlistname"]/a'
28
-xpath_torrent_file = './/td[@class="tlistdownload"]/a'
29
-xpath_filesize = './/td[@class="tlistsize"]/text()'
30
-xpath_seeds = './/td[@class="tlistsn"]/text()'
31
-xpath_leeches = './/td[@class="tlistln"]/text()'
32
-xpath_downloads = './/td[@class="tlistdn"]/text()'
33
-
34
-
35
-# convert a variable to integer or return 0 if it's not a number
36
-def int_or_zero(num):
37
-    if isinstance(num, list):
38
-        if len(num) < 1:
39
-            return 0
40
-        num = num[0]
41
-    if num.isdigit():
42
-        return int(num)
43
-    return 0
44
-
45
-
46
-# get multiplier to convert torrent size to bytes
47
-def get_filesize_mul(suffix):
48
-    return {
49
-        'KB': 1024,
50
-        'MB': 1024 ** 2,
51
-        'GB': 1024 ** 3,
52
-        'TB': 1024 ** 4,
53
-
54
-        'KIB': 1024,
55
-        'MIB': 1024 ** 2,
56
-        'GIB': 1024 ** 3,
57
-        'TIB': 1024 ** 4
58
-    }[str(suffix).upper()]
26
+xpath_results = '//table[contains(@class, "torrent-list")]//tr[not(th)]'
27
+xpath_category = './/td[1]/a[1]'
28
+xpath_title = './/td[2]/a[last()]'
29
+xpath_torrent_links = './/td[3]/a'
30
+xpath_filesize = './/td[4]/text()'
31
+xpath_seeds = './/td[6]/text()'
32
+xpath_leeches = './/td[7]/text()'
33
+xpath_downloads = './/td[8]/text()'
59 34
 
60 35
 
61 36
 # do search-request
@@ -72,25 +47,32 @@ def response(resp):
72 47
     dom = html.fromstring(resp.text)
73 48
 
74 49
     for result in dom.xpath(xpath_results):
50
+        # defaults
51
+        filesize = 0
52
+        magnet_link = ""
53
+        torrent_link = ""
54
+
75 55
         # category in which our torrent belongs
76
-        category = result.xpath(xpath_category)[0].attrib.get('title')
56
+        try:
57
+            category = result.xpath(xpath_category)[0].attrib.get('title')
58
+        except:
59
+            pass
77 60
 
78 61
         # torrent title
79 62
         page_a = result.xpath(xpath_title)[0]
80 63
         title = extract_text(page_a)
81 64
 
82 65
         # link to the page
83
-        href = page_a.attrib.get('href')
66
+        href = base_url + page_a.attrib.get('href')
84 67
 
85
-        # link to the torrent file
86
-        torrent_link = result.xpath(xpath_torrent_file)[0].attrib.get('href')
87
-
88
-        # torrent size
89
-        try:
90
-            file_size, suffix = result.xpath(xpath_filesize)[0].split(' ')
91
-            file_size = int(float(file_size) * get_filesize_mul(suffix))
92
-        except:
93
-            file_size = None
68
+        for link in result.xpath(xpath_torrent_links):
69
+            url = link.attrib.get('href')
70
+            if 'magnet' in url:
71
+                # link to the magnet
72
+                magnet_link = url
73
+            else:
74
+                # link to the torrent file
75
+                torrent_link = url
94 76
 
95 77
         # seed count
96 78
         seed = int_or_zero(result.xpath(xpath_seeds))
@@ -101,6 +83,14 @@ def response(resp):
101 83
         # torrent downloads count
102 84
         downloads = int_or_zero(result.xpath(xpath_downloads))
103 85
 
86
+        # let's try to calculate the torrent size
87
+        try:
88
+            filesize_info = result.xpath(xpath_filesize)[0]
89
+            filesize, filesize_multiplier = filesize_info.split()
90
+            filesize = get_torrent_size(filesize, filesize_multiplier)
91
+        except:
92
+            pass
93
+
104 94
         # content string contains all information not included into template
105 95
         content = 'Category: "{category}". Downloaded {downloads} times.'
106 96
         content = content.format(category=category, downloads=downloads)
@@ -110,8 +100,9 @@ def response(resp):
110 100
                         'content': content,
111 101
                         'seed': seed,
112 102
                         'leech': leech,
113
-                        'filesize': file_size,
103
+                        'filesize': filesize,
114 104
                         'torrentfile': torrent_link,
105
+                        'magnetlink': magnet_link,
115 106
                         'template': 'torrent.html'})
116 107
 
117 108
     return results

+ 1
- 1
searx/engines/swisscows.py View File

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

+ 2
- 3
searx/engines/tokyotoshokan.py View File

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

+ 22
- 16
searx/engines/torrentz.py View File

@@ -1,7 +1,7 @@
1 1
 """
2
- Torrentz.eu (BitTorrent meta-search engine)
2
+ Torrentz2.eu (BitTorrent meta-search engine)
3 3
 
4
- @website      https://torrentz.eu/
4
+ @website      https://torrentz2.eu/
5 5
  @provide-api  no
6 6
 
7 7
  @using-api    no
@@ -14,24 +14,24 @@
14 14
 import re
15 15
 from lxml import html
16 16
 from datetime import datetime
17
-from searx.engines.nyaa import int_or_zero, get_filesize_mul
18 17
 from searx.engines.xpath import extract_text
19 18
 from searx.url_utils import urlencode
19
+from searx.utils import get_torrent_size
20 20
 
21 21
 # engine dependent config
22 22
 categories = ['files', 'videos', 'music']
23 23
 paging = True
24 24
 
25 25
 # search-url
26
-# https://torrentz.eu/search?f=EXAMPLE&p=6
27
-base_url = 'https://torrentz.eu/'
26
+# https://torrentz2.eu/search?f=EXAMPLE&p=6
27
+base_url = 'https://torrentz2.eu/'
28 28
 search_url = base_url + 'search?{query}'
29 29
 
30 30
 
31 31
 # do search-request
32 32
 def request(query, params):
33 33
     page = params['pageno'] - 1
34
-    query = urlencode({'q': query, 'p': page})
34
+    query = urlencode({'f': query, 'p': page})
35 35
     params['url'] = search_url.format(query=query)
36 36
     return params
37 37
 
@@ -54,22 +54,29 @@ def response(resp):
54 54
         # extract url and remove a slash in the beginning
55 55
         link = links[0].attrib.get('href').lstrip('/')
56 56
 
57
-        seed = result.xpath('./dd/span[@class="u"]/text()')[0].replace(',', '')
58
-        leech = result.xpath('./dd/span[@class="d"]/text()')[0].replace(',', '')
57
+        seed = 0
58
+        leech = 0
59
+        try:
60
+            seed = int(result.xpath('./dd/span[4]/text()')[0].replace(',', ''))
61
+            leech = int(result.xpath('./dd/span[5]/text()')[0].replace(',', ''))
62
+        except:
63
+            pass
59 64
 
60 65
         params = {
61 66
             'url': base_url + link,
62 67
             'title': title,
63
-            'seed': int_or_zero(seed),
64
-            'leech': int_or_zero(leech),
68
+            'seed': seed,
69
+            'leech': leech,
65 70
             'template': 'torrent.html'
66 71
         }
67 72
 
68 73
         # let's try to calculate the torrent size
69 74
         try:
70
-            size_str = result.xpath('./dd/span[@class="s"]/text()')[0]
71
-            size, suffix = size_str.split()
72
-            params['filesize'] = int(size) * get_filesize_mul(suffix)
75
+            filesize_info = result.xpath('./dd/span[3]/text()')[0]
76
+            filesize, filesize_multiplier = filesize_info.split()
77
+            filesize = get_torrent_size(filesize, filesize_multiplier)
78
+
79
+            params['filesize'] = filesize
73 80
         except:
74 81
             pass
75 82
 
@@ -80,9 +87,8 @@ def response(resp):
80 87
 
81 88
         # extract and convert creation date
82 89
         try:
83
-            date_str = result.xpath('./dd/span[@class="a"]/span')[0].attrib.get('title')
84
-            # Fri, 25 Mar 2016 16:29:01
85
-            date = datetime.strptime(date_str, '%a, %d %b %Y %H:%M:%S')
90
+            date_ts = result.xpath('./dd/span[2]')[0].attrib.get('title')
91
+            date = datetime.fromtimestamp(float(date_ts))
86 92
             params['publishedDate'] = date
87 93
         except:
88 94
             pass

+ 8
- 10
searx/languages.py View File

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

+ 28
- 28
searx/settings.yml View File

@@ -189,11 +189,10 @@ engines:
189 189
     shortcut : et
190 190
     disabled : True
191 191
 
192
-# api-key required: http://www.faroo.com/hp/api/api.html#key
193
-#  - name : faroo
194
-#    engine : faroo
195
-#    shortcut : fa
196
-#    api_key : 'apikey' # required!
192
+  - name : faroo
193
+    engine : faroo
194
+    shortcut : fa
195
+    disabled : True
197 196
 
198 197
   - name : 500px
199 198
     engine : www500px
@@ -247,15 +246,16 @@ engines:
247 246
     disabled: True
248 247
 
249 248
   - name : gitlab
250
-    engine : xpath
249
+    engine : json_engine
251 250
     paging : True
252
-    search_url : https://gitlab.com/search?page={pageno}&search={query}
253
-    url_xpath : //li[@class="project-row"]//a[@class="project"]/@href
254
-    title_xpath : //li[@class="project-row"]//span[contains(@class, "project-full-name")]
255
-    content_xpath : //li[@class="project-row"]//div[@class="description"]/p
251
+    search_url : https://gitlab.com/api/v4/projects?search={query}&page={pageno}
252
+    url_query : web_url
253
+    title_query : name_with_namespace
254
+    content_query : description
255
+    page_size : 20
256 256
     categories : it
257 257
     shortcut : gl
258
-    timeout : 5.0
258
+    timeout : 10.0
259 259
     disabled : True
260 260
 
261 261
   - name : github
@@ -326,9 +326,9 @@ engines:
326 326
     engine : xpath
327 327
     paging : True
328 328
     search_url : https://geektimes.ru/search/page{pageno}/?q={query}
329
-    url_xpath : //div[@class="search_results"]//a[@class="post__title_link"]/@href
330
-    title_xpath : //div[@class="search_results"]//a[@class="post__title_link"]
331
-    content_xpath : //div[@class="search_results"]//div[contains(@class, "content")]
329
+    url_xpath : //article[contains(@class, "post")]//a[@class="post__title_link"]/@href
330
+    title_xpath : //article[contains(@class, "post")]//a[@class="post__title_link"]
331
+    content_xpath : //article[contains(@class, "post")]//div[contains(@class, "post__text")]
332 332
     categories : it
333 333
     timeout : 4.0
334 334
     disabled : True
@@ -338,9 +338,9 @@ engines:
338 338
     engine : xpath
339 339
     paging : True
340 340
     search_url : https://habrahabr.ru/search/page{pageno}/?q={query}
341
-    url_xpath : //div[@class="search_results"]//a[contains(@class, "post__title_link")]/@href
342
-    title_xpath : //div[@class="search_results"]//a[contains(@class, "post__title_link")]
343
-    content_xpath : //div[@class="search_results"]//div[contains(@class, "content")]
341
+    url_xpath : //article[contains(@class, "post")]//a[@class="post__title_link"]/@href
342
+    title_xpath : //article[contains(@class, "post")]//a[@class="post__title_link"]
343
+    content_xpath : //article[contains(@class, "post")]//div[contains(@class, "post__text")]
344 344
     categories : it
345 345
     timeout : 4.0
346 346
     disabled : True
@@ -556,6 +556,12 @@ engines:
556 556
     timeout : 6.0
557 557
     disabled : True
558 558
 
559
+  - name : torrentz
560
+    engine : torrentz
561
+    shortcut : tor
562
+    url: https://torrentz2.eu/
563
+    timeout : 3.0
564
+
559 565
   - name : twitter
560 566
     engine : twitter
561 567
     shortcut : tw
@@ -579,6 +585,7 @@ engines:
579 585
   - name : yahoo
580 586
     engine : yahoo
581 587
     shortcut : yh
588
+    disabled : True
582 589
 
583 590
   - name : yandex
584 591
     engine : yandex
@@ -639,10 +646,10 @@ engines:
639 646
     engine: xpath
640 647
     shortcut: vo
641 648
     categories: social media
642
-    search_url : https://voat.co/search?q={query}
643
-    url_xpath : //p[contains(@class, "title")]/a/@href
644
-    title_xpath : //p[contains(@class, "title")]/a
645
-    content_xpath : //span[@class="domain"]
649
+    search_url : https://searchvoat.co/?t={query}
650
+    url_xpath : //div[@class="entry"]/p/a[@class="title"]/@href
651
+    title_xpath : //div[@class="entry"]/p/a[@class="title"]
652
+    content_xpath : //div[@class="entry"]/p/span[@class="domain"]
646 653
     timeout : 10.0
647 654
     disabled : True
648 655
 
@@ -651,12 +658,6 @@ engines:
651 658
     shortcut : 1337x
652 659
     disabled : True
653 660
 
654
-#The blekko technology and team have joined IBM Watson! -> https://blekko.com/
655
-#  - name : blekko images
656
-#    engine : blekko_images
657
-#    locale : en-US
658
-#    shortcut : bli
659
-
660 661
 #  - name : yacy
661 662
 #    engine : yacy
662 663
 #    shortcut : ya
@@ -676,7 +677,6 @@ locales:
676 677
     bg : Български (Bulgarian)
677 678
     cs : Čeština (Czech)
678 679
     de : Deutsch (German)
679
-    de_DE : Deutsch (German_Germany)
680 680
     el_GR : Ελληνικά (Greek_Greece)
681 681
     eo : Esperanto (Esperanto)
682 682
     es : Español (Spanish)

+ 1
- 8
searx/static/themes/oscar/css/logicodev.min.css
File diff suppressed because it is too large
View File


+ 1
- 1
searx/static/themes/oscar/css/pointhi.min.css
File diff suppressed because it is too large
View File


+ 1
- 1
searx/static/themes/oscar/js/searx.min.js View File

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

+ 2
- 0
searx/static/themes/oscar/less/logicodev/oscar.less View File

@@ -19,3 +19,5 @@
19 19
 @import "cursor.less";
20 20
 
21 21
 @import "code.less";
22
+
23
+@import "preferences.less";

+ 3
- 0
searx/static/themes/oscar/less/logicodev/preferences.less View File

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

+ 2
- 0
searx/static/themes/oscar/less/pointhi/oscar.less View File

@@ -17,3 +17,5 @@
17 17
 @import "code.less";
18 18
 
19 19
 @import "navbar.less";
20
+
21
+@import "preferences.less";

+ 3
- 0
searx/static/themes/oscar/less/pointhi/preferences.less View File

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

+ 11
- 11
searx/templates/courgette/result_templates/code.html View File

@@ -1,11 +1,11 @@
1
-<div class="result {{ result.class }}">
2
-    <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>
3
-    {% if result.publishedDate %}<span class="published_date">{{ result.publishedDate }}</span>{% endif %}
4
-    <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>
5
-    {% 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 %}
6
-    <div dir="ltr">
7
-    {{ result.codelines|code_highlighter(result.code_language)|safe }}
8
-	</div>
9
-
10
-    <p class="url">{{ result.pretty_url }}&lrm;</p>
11
-</div>
1
+<div class="result {{ result.class }}">
2
+    <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>
3
+    {% if result.publishedDate %}<span class="published_date">{{ result.publishedDate }}</span>{% endif %}
4
+    <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>
5
+    {% 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 %}
6
+    <div dir="ltr">
7
+    {{ result.codelines|code_highlighter(result.code_language)|safe }}
8
+	</div>
9
+
10
+    <p class="url">{{ result.pretty_url }}&lrm;</p>
11
+</div>

+ 11
- 11
searx/templates/legacy/result_templates/code.html View File

@@ -1,11 +1,11 @@
1
-<div class="result {{ result.class }}">
2
-    <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>
3
-    <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>
4
-    {% if result.publishedDate %}<p class="published_date">{{ result.publishedDate }}</p>{% endif %}
5
-    <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>
6
-    {% 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 %}
7
-    
8
-    <div dir="ltr">
9
-    {{ result.codelines|code_highlighter(result.code_language)|safe }}
10
-	</div>
11
-</div>
1
+<div class="result {{ result.class }}">
2
+    <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>
3
+    <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>
4
+    {% if result.publishedDate %}<p class="published_date">{{ result.publishedDate }}</p>{% endif %}
5
+    <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>
6
+    {% 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 %}
7
+    
8
+    <div dir="ltr">
9
+    {{ result.codelines|code_highlighter(result.code_language)|safe }}
10
+	</div>
11
+</div>

+ 99
- 88
searx/templates/oscar/macros.html View File

@@ -1,88 +1,99 @@
1
-<!-- Draw glyphicon icon from bootstrap-theme -->
2
-{% macro icon(action) -%}
3
-    <span class="glyphicon glyphicon-{{ action }}"></span>
4
-{%- endmacro %}
5
-
6
-<!-- Draw favicon -->
7
-<!-- TODO: using url_for methode -->
8
-{% macro draw_favicon(favicon) -%}
9
-    <img width="32" height="32" class="favicon" src="static/themes/oscar/img/icons/{{ favicon }}.png" alt="{{ favicon }}" />
10
-{%- endmacro %}
11
-
12
-{%- macro result_link(url, title, classes='') -%}
13
-<a href="{{ url }}" {% if classes %}class="{{ classes }}" {% endif %}{% if results_on_new_tab %}target="_blank" rel="noopener noreferrer"{% else %}rel="noreferrer"{% endif %}>{{ title }}</a>
14
-{%- endmacro -%}
15
-
16
-<!-- Draw result header -->
17
-{% macro result_header(result, favicons) -%}
18
-<h4 class="result_header">{% if result.engine~".png" in favicons %}{{ draw_favicon(result.engine) }} {% endif %}{{ result_link(result.url, result.title|safe) }}</h4>
19
-{%- endmacro %}
20
-
21
-<!-- Draw result sub header -->
22
-{% macro result_sub_header(result) -%}
23
-    {% if result.publishedDate %}<time class="text-muted" datetime="{{ result.pubdate }}" >{{ result.publishedDate }}</time>{% endif %}
24
-    {% if result.magnetlink %}<small> &bull; {{ result_link(result.magnetlink, icon('magnet') + _('magnet link'), "magnetlink") }}</small>{% endif %}
25
-    {% if result.torrentfile %}<small> &bull; {{ result_link(result.torrentfile, icon('download-alt') + _('torrent file'), "torrentfile") }}</small>{% endif %}
26
-{%- endmacro %}
27
-
28
-<!-- Draw result footer -->
29
-{% macro result_footer(result) -%}
30
-    <div class="clearfix"></div>
31
-    <div class="pull-right">
32
-    {% for engine in result.engines %}
33
-        <span class="label label-default">{{ engine }}</span>
34
-    {% endfor %}
35
-    <small>{{ result_link("https://web.archive.org/web/" + result.url, icon('link') + _('cached'), "text-info") }}</small>
36
-    {% if proxify %}
37
-    <small>{{ result_link(proxify(result.url), icon('sort') + _('proxied'), "text-info") }}</small>
38
-    {% endif %}
39
-</div>
40
-<div class="external-link">{{ result.pretty_url }}</div>
41
-{%- endmacro %}
42
-
43
-<!-- Draw result footer -->
44
-{% macro result_footer_rtl(result) -%}
45
-    <div class="clearfix"></div>
46
-    {% for engine in result.engines %}
47
-        <span class="label label-default">{{ engine }}</span>
48
-    {% endfor %}
49
-    <small>{{ result_link("https://web.archive.org/web/" + result.url, icon('link') + _('cached'), "text-info") }}</small>
50
-    {% if proxify %}
51
-    <small>{{ result_link(proxify(result.url), icon('sort') + _('proxied'), "text-info") }}</small>
52
-    {% endif %}
53
-    <div class="external-link">{{ result.pretty_url }}</div>
54
-{%- endmacro %}
55
-
56
-{% macro preferences_item_header(info, label, rtl) -%}
57
-    {% if rtl %}
58
-    <div class="row form-group">
59
-        <label class="col-sm-3 col-md-2 pull-right">{{ label }}</label>
60
-        <span class="col-sm-5 col-md-6 help-block pull-left">{{ info }}</span>
61
-        <div class="col-sm-4 col-md-4">
62
-    {% else %}
63
-    <div class="row form-group">
64
-        <label class="col-sm-3 col-md-2">{{ label }}</label>
65
-        <div class="col-sm-4 col-md-4">
66
-    {% endif %}
67
-{%- endmacro %}
68
-
69
-{% macro preferences_item_footer(info, label, rtl) -%}
70
-    {% if rtl %}
71
-        </div>
72
-    </div>
73
-    {% else %}
74
-        </div>
75
-        <span class="col-sm-5 col-md-6 help-block">{{ info }}</span>
76
-    </div>
77
-    {% endif %}
78
-{%- endmacro %}
79
-
80
-{% macro checkbox_toggle(id, blocked) -%}
81
-    <div class="onoffswitch">
82
-        <input type="checkbox" id="{{ id }}" name="{{ id }}"{% if blocked %} checked="checked"{% endif %} class="onoffswitch-checkbox">
83
-        <label class="onoffswitch-label" for="{{ id }}">
84
-            <span class="onoffswitch-inner"></span>
85
-            <span class="onoffswitch-switch"></span>
86
-        </label>
87
-    </div>
88
-{%- endmacro %}
1
+<!-- Draw glyphicon icon from bootstrap-theme -->
2
+{% macro icon(action) -%}
3
+    <span class="glyphicon glyphicon-{{ action }}"></span>
4
+{%- endmacro %}
5
+
6
+<!-- Draw favicon -->
7
+{% macro draw_favicon(favicon) -%}
8
+    <img width="32" height="32" class="favicon" src="{{ url_for('static', filename='themes/oscar/img/icons/' + favicon + '.png') }}" alt="{{ favicon }}" />
9
+{%- endmacro %}
10
+
11
+{%- macro result_link(url, title, classes='') -%}
12
+<a href="{{ url }}" {% if classes %}class="{{ classes }}" {% endif %}{% if results_on_new_tab %}target="_blank" rel="noopener noreferrer"{% else %}rel="noreferrer"{% endif %}>{{ title }}</a>
13
+{%- endmacro -%}
14
+
15
+<!-- Draw result header -->
16
+{% macro result_header(result, favicons) -%}
17
+<h4 class="result_header">{% if result.engine~".png" in favicons %}{{ draw_favicon(result.engine) }} {% endif %}{{ result_link(result.url, result.title|safe) }}</h4>
18
+{%- endmacro %}
19
+
20
+<!-- Draw result sub header -->
21
+{% macro result_sub_header(result) -%}
22
+    {% if result.publishedDate %}<time class="text-muted" datetime="{{ result.pubdate }}" >{{ result.publishedDate }}</time>{% endif %}
23
+    {% if result.magnetlink %}<small> &bull; {{ result_link(result.magnetlink, icon('magnet') + _('magnet link'), "magnetlink") }}</small>{% endif %}
24
+    {% if result.torrentfile %}<small> &bull; {{ result_link(result.torrentfile, icon('download-alt') + _('torrent file'), "torrentfile") }}</small>{% endif %}
25
+{%- endmacro %}
26
+
27
+<!-- Draw result footer -->
28
+{% macro result_footer(result) -%}
29
+    <div class="clearfix"></div>
30
+    <div class="pull-right">
31
+    {% for engine in result.engines %}
32
+        <span class="label label-default">{{ engine }}</span>
33
+    {% endfor %}
34
+    <small>{{ result_link("https://web.archive.org/web/" + result.url, icon('link') + _('cached'), "text-info") }}</small>
35
+    {% if proxify %}
36
+    <small>{{ result_link(proxify(result.url), icon('sort') + _('proxied'), "text-info") }}</small>
37
+    {% endif %}
38
+</div>
39
+<div class="external-link">{{ result.pretty_url }}</div>
40
+{%- endmacro %}
41
+
42
+<!-- Draw result footer -->
43
+{% macro result_footer_rtl(result) -%}
44
+    <div class="clearfix"></div>
45
+    {% for engine in result.engines %}
46
+        <span class="label label-default">{{ engine }}</span>
47
+    {% endfor %}
48
+    <small>{{ result_link("https://web.archive.org/web/" + result.url, icon('link') + _('cached'), "text-info") }}</small>
49
+    {% if proxify %}
50
+    <small>{{ result_link(proxify(result.url), icon('sort') + _('proxied'), "text-info") }}</small>
51
+    {% endif %}
52
+    <div class="external-link">{{ result.pretty_url }}</div>
53
+{%- endmacro %}
54
+
55
+{% macro preferences_item_header(info, label, rtl) -%}
56
+    {% if rtl %}
57
+    <div class="row form-group">
58
+        <label class="col-sm-3 col-md-2 pull-right">{{ label }}</label>
59
+        <span class="col-sm-5 col-md-6 help-block pull-left">{{ info }}</span>
60
+        <div class="col-sm-4 col-md-4">
61
+    {% else %}
62
+    <div class="row form-group">
63
+        <label class="col-sm-3 col-md-2">{{ label }}</label>
64
+        <div class="col-sm-4 col-md-4">
65
+    {% endif %}
66
+{%- endmacro %}
67
+
68
+{% macro preferences_item_footer(info, label, rtl) -%}
69
+    {% if rtl %}
70
+        </div>
71
+    </div>
72
+    {% else %}
73
+        </div>
74
+        <span class="col-sm-5 col-md-6 help-block">{{ info }}</span>
75
+    </div>
76
+    {% endif %}
77
+{%- endmacro %}
78
+
79
+{% macro checkbox_toggle(id, blocked) -%}
80
+    <div class="onoffswitch">
81
+        <input type="checkbox" id="{{ id }}" name="{{ id }}"{% if blocked %} checked="checked"{% endif %} class="onoffswitch-checkbox">
82
+        <label class="onoffswitch-label" for="{{ id }}">
83
+            <span class="onoffswitch-inner"></span>
84
+            <span class="onoffswitch-switch"></span>
85
+        </label>
86
+    </div>
87
+{%- endmacro %}
88
+
89
+{% macro support_toggle(supports) -%}
90
+    {% if supports %}
91
+    <span class="label label-success">
92
+        {{ _("supported") }}
93
+    </span>
94
+    {% else %}
95
+    <span class="label label-danger">
96
+        {{ _("not supported") }}
97
+    </span>
98
+    {% endif %}
99
+{%- endmacro %}

+ 17
- 14
searx/templates/oscar/preferences.html View File

@@ -1,7 +1,8 @@
1
-{% from 'oscar/macros.html' import preferences_item_header, preferences_item_header_rtl, preferences_item_footer, preferences_item_footer_rtl, checkbox_toggle %}
1
+{% from 'oscar/macros.html' import preferences_item_header, preferences_item_header_rtl, preferences_item_footer, preferences_item_footer_rtl, checkbox_toggle, support_toggle %}
2 2
 {% extends "oscar/base.html" %}
3 3
 {% block title %}{{ _('preferences') }} - {% endblock %}
4 4
 {% block content %}
5
+
5 6
 <div>
6 7
 
7 8
     <h1>{{ _('Preferences') }}</h1>
@@ -148,7 +149,7 @@
148 149
 				    <th>{{ _("Allow") }}</th>
149 150
 				    <th>{{ _("Engine name") }}</th>
150 151
 				    <th>{{ _("Shortcut") }}</th>
151
-				    <th>{{ _("Supports selected language") }}</th>
152
+				    <th>{{ _("Selected language") }}</th>
152 153
 				    <th>{{ _("SafeSearch") }}</th>
153 154
 				    <th>{{ _("Time range") }}</th>
154 155
 				    <th>{{ _("Avg. time") }}</th>
@@ -156,8 +157,9 @@
156 157
                                     {% else %}
157 158
 				    <th>{{ _("Max time") }}</th>
158 159
 				    <th>{{ _("Avg. time") }}</th>
160
+				    <th>{{ _("Time range") }}</th>
159 161
 				    <th>{{ _("SafeSearch") }}</th>
160
-				    <th>{{ _("Supports selected language") }}</th>
162
+				    <th>{{ _("Selected language") }}</th>
161 163
 				    <th>{{ _("Shortcut") }}</th>
162 164
 				    <th>{{ _("Engine name") }}</th>
163 165
 				    <th>{{ _("Allow") }}</th>
@@ -172,17 +174,18 @@
172 174
                                     </td>
173 175
                                     <th>{{ search_engine.name }}</th>
174 176
 				    <td class="name">{{ shortcuts[search_engine.name] }}</td>
175
-				    <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>
176
-				    <td><input type="checkbox" {{ "checked" if search_engine.safesearch==True else ""}} readonly="readonly" disabled="disabled"></td>
177
-				    <td><input type="checkbox" {{ "checked" if search_engine.time_range_support==True else ""}} readonly="readonly" disabled="disabled"></td>
178
-				    <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>
179
-				    <td class="{{ 'danger' if stats[search_engine.name]['warn_timeout'] else '' }}">{{ search_engine.timeout }}</td>
180
-                                    {% else %}
181
-				    <td class="{{ 'danger' if stats[search_engine.name]['warn_timeout'] else '' }}">{{ search_engine.timeout }}</td>
182
-				    <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>
183
-				    <td><input type="checkbox" {{ "checked" if search_engine.safesearch==True else ""}} readonly="readonly" disabled="disabled"></td>
184
-				    <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>
185
-				    <td>{{ shortcuts[search_engine.name] }}</td>
177
+					<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>
178
+					<td>{{ support_toggle(search_engine.safesearch==True) }}</td>
179
+					<td>{{ support_toggle(search_engine.time_range_support==True) }}</td>
180
+					<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>
181
+					<td class="{{ 'danger' if stats[search_engine.name]['warn_timeout'] else '' }}">{{ search_engine.timeout }}</td>
182
+									{% else %}
183
+					<td class="{{ 'danger' if stats[search_engine.name]['warn_timeout'] else '' }}">{{ search_engine.timeout }}</td>
184
+					<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>
185
+					<td>{{ support_toggle(search_engine.time_range_support==True) }}</td>
186
+					<td>{{ support_toggle(search_engine.safesearch==True) }}</td>
187
+					<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>
188
+					<td>{{ shortcuts[search_engine.name] }}</td>
186 189
                                     <th>{{ search_engine.name }}</th>
187 190
                                     <td class="onoff-checkbox">
188 191
                                         {{ checkbox_toggle('engine_' + search_engine.name|replace(' ', '_') + '__' + categ|replace(' ', '_'), (search_engine.name, categ) in disabled_engines) }}

+ 1
- 2
searx/templates/simple/macros.html View File

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

BIN
searx/translations/de_DE/LC_MESSAGES/messages.mo View File


+ 0
- 844
searx/translations/de_DE/LC_MESSAGES/messages.po View File

@@ -1,844 +0,0 @@
1
-# Translations template for PROJECT.
2
-# Copyright (C) 2016 ORGANIZATION
3
-# This file is distributed under the same license as the PROJECT project.
4
-# 
5
-# Translators:
6
-# Bamstam, 2016-2017
7
-# Benjamin Richter <benjamin@hacktherack.de>, 2015
8
-# cy8aer <cybaer42@web.de>, 2016-2017
9
-msgid ""
10
-msgstr ""
11
-"Project-Id-Version: searx\n"
12
-"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
13
-"POT-Creation-Date: 2016-12-29 10:42+0100\n"
14
-"PO-Revision-Date: 2017-05-19 20:17+0000\n"
15
-"Last-Translator: cy8aer <cybaer42@web.de>\n"
16
-"Language-Team: German (Germany) (http://www.transifex.com/asciimoo/searx/language/de_DE/)\n"
17
-"MIME-Version: 1.0\n"
18
-"Content-Type: text/plain; charset=UTF-8\n"
19
-"Content-Transfer-Encoding: 8bit\n"
20
-"Generated-By: Babel 2.3.4\n"
21
-"Language: de_DE\n"
22
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
23
-
24
-#: searx/webapp.py:123
25
-msgid "files"
26
-msgstr "Dateien"
27
-
28
-#: searx/webapp.py:124
29
-msgid "general"
30
-msgstr "Allgemein"
31
-
32
-#: searx/webapp.py:125
33
-msgid "music"
34
-msgstr "Musik"
35
-
36
-#: searx/webapp.py:126
37
-msgid "social media"
38
-msgstr "Soziale Medien"
39
-
40
-#: searx/webapp.py:127
41
-msgid "images"
42
-msgstr "Fotos"
43
-
44
-#: searx/webapp.py:128
45
-msgid "videos"
46
-msgstr "Videos"
47
-
48
-#: searx/webapp.py:129
49
-msgid "it"
50
-msgstr "IT"
51
-
52
-#: searx/webapp.py:130
53
-msgid "news"
54
-msgstr "Nachrichten"
55
-
56
-#: searx/webapp.py:131
57
-msgid "map"
58
-msgstr "Karten"
59
-
60
-#: searx/webapp.py:132
61
-msgid "science"
62
-msgstr "Wissenschaft"
63
-
64
-#: searx/webapp.py:384 searx/webapp.py:594
65
-msgid "Invalid settings, please edit your preferences"
66
-msgstr "Ungültige Auswahl, bitte überprüfen Sie die Einstellungen"
67
-
68
-#: searx/webapp.py:425
69
-msgid "search error"
70
-msgstr "Fehler bei der Suche"
71
-
72
-#: searx/webapp.py:467
73
-msgid "{minutes} minute(s) ago"
74
-msgstr "vor {minutes} Minute(n)"
75
-
76
-#: searx/webapp.py:469
77
-msgid "{hours} hour(s), {minutes} minute(s) ago"
78
-msgstr "vor {hours} Stunde(n). {minutes} Minute(n)"
79
-
80
-#: searx/answerers/random/answerer.py:48
81
-msgid "Random value generator"
82
-msgstr "Zufallswertgenerator"
83
-
84
-#: searx/answerers/random/answerer.py:49
85
-msgid "Generate different random values"
86
-msgstr "Zufallswerte generieren"
87
-
88
-#: searx/answerers/statistics/answerer.py:49
89
-msgid "Statistics functions"
90
-msgstr "Statistik-Funktionen"
91
-
92
-#: searx/answerers/statistics/answerer.py:50
93
-msgid "Compute {functions} of the arguments"
94
-msgstr "{functions} der Argumente berechnen"
95
-
96
-#: searx/engines/__init__.py:192
97
-msgid "Engine time (sec)"
98
-msgstr "Zeitbedarf (s)"
99
-
100
-#: searx/engines/__init__.py:196
101
-msgid "Page loads (sec)"
102
-msgstr "Ladezeit (s)"
103
-
104
-#: searx/engines/__init__.py:200 searx/templates/oscar/results.html:88
105
-msgid "Number of results"
106
-msgstr "Anzahl Ergebnisse"
107
-
108
-#: searx/engines/__init__.py:204
109
-msgid "Scores"
110
-msgstr "Punktwerte"
111
-
112
-#: searx/engines/__init__.py:208
113
-msgid "Scores per result"
114
-msgstr "Punktwerte pro Ergebnis"
115
-
116
-#: searx/engines/__init__.py:212
117
-msgid "Errors"
118
-msgstr "Fehler"
119
-
120
-#: searx/engines/pdbe.py:87
121
-msgid "{title}&nbsp;(OBSOLETE)"
122
-msgstr "{title}&nbsp;(OBSOLET)"
123
-
124
-#: searx/engines/pdbe.py:91
125
-msgid "This entry has been superseded by"
126
-msgstr "Dieser Eintrag wurde ersetzt durch"
127
-
128
-#: searx/plugins/doai_rewrite.py:7
129
-msgid "DOAI rewrite"
130
-msgstr "DOAI-Umgehung"
131
-
132
-#: searx/plugins/doai_rewrite.py:8
133
-msgid ""
134
-"Avoid paywalls by redirecting to open-access versions of publications when "
135
-"available"
136
-msgstr "Paywalls umgehen, indem wenn möglich auf Open-Access-Versionen von Publikationen umgeleitet wird"
137
-
138
-#: searx/plugins/https_rewrite.py:29
139
-msgid "Rewrite HTTP links to HTTPS if possible"
140
-msgstr "Umschreiben von HTTP-Links nach HTTPS, wenn möglich"
141
-
142
-#: searx/plugins/infinite_scroll.py:3
143
-msgid "Infinite scroll"
144
-msgstr "Unbegrenztes Scrollen"
145
-
146
-#: searx/plugins/infinite_scroll.py:4
147
-msgid "Automatically load next page when scrolling to bottom of current page"
148
-msgstr "Nächste Seite automatisch laden, wenn zum Seitenende gescrollt wird"
149
-
150
-#: searx/plugins/open_results_on_new_tab.py:18
151
-#: searx/templates/oscar/preferences.html:113
152
-msgid "Open result links on new browser tabs"
153
-msgstr "Öffne Links in einem neuen Browser-Tab"
154
-
155
-#: searx/plugins/open_results_on_new_tab.py:19
156
-msgid ""
157
-"Results are opened in the same window by default. This plugin overwrites the"
158
-" default behaviour to open links on new tabs/windows. (JavaScript required)"
159
-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)."
160
-
161
-#: searx/plugins/search_on_category_select.py:18
162
-msgid "Search on category select"
163
-msgstr "Suchen nach Kategorie"
164
-
165
-#: searx/plugins/search_on_category_select.py:19
166
-msgid ""
167
-"Perform search immediately if a category selected. Disable to select "
168
-"multiple categories. (JavaScript required)"
169
-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)."
170
-
171
-#: searx/plugins/self_info.py:20
172
-msgid ""
173
-"Displays your IP if the query is \"ip\" and your user agent if the query "
174
-"contains \"user agent\"."
175
-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."
176
-
177
-#: searx/plugins/tracker_url_remover.py:26
178
-msgid "Tracker URL remover"
179
-msgstr "Tracking-URLs bereinigen"
180
-
181
-#: searx/plugins/tracker_url_remover.py:27
182
-msgid "Remove trackers arguments from the returned URL"
183
-msgstr "Tracker-Argumente der erhaltenen URL entfernen"
184
-
185
-#: searx/plugins/vim_hotkeys.py:3
186
-msgid "Vim-like hotkeys"
187
-msgstr "Vim-ähnliche Hotkeys"
188
-
189
-#: searx/plugins/vim_hotkeys.py:4
190
-msgid ""
191
-"Navigate search results with Vim-like hotkeys (JavaScript required). Press "
192
-"\"h\" key on main or result page to get help."
193
-msgstr "Durch Suchergebnisse navigieren mit Vim-ähnlichen Hotkeys (benötigt JavaScript). \"h\" drücken auf der Hauptseite oder der Ergebnisseite, um Hilfe zu erhalten."
194
-
195
-#: searx/templates/courgette/404.html:4 searx/templates/legacy/404.html:4
196
-#: searx/templates/oscar/404.html:4 searx/templates/pix-art/404.html:4
197
-msgid "Page not found"
198
-msgstr "Seite nicht gefunden"
199
-
200
-#: searx/templates/courgette/404.html:6 searx/templates/legacy/404.html:6
201
-#: searx/templates/oscar/404.html:6 searx/templates/pix-art/404.html:6
202
-#, python-format
203
-msgid "Go to %(search_page)s."
204
-msgstr "Gehe zu %(search_page)s."
205
-
206
-#: searx/templates/courgette/404.html:6 searx/templates/legacy/404.html:6
207
-#: searx/templates/oscar/404.html:6 searx/templates/pix-art/404.html:6
208
-msgid "search page"
209
-msgstr "Seite durchsuchen"
210
-
211
-#: searx/templates/courgette/index.html:9
212
-#: searx/templates/courgette/index.html:13
213
-#: searx/templates/courgette/results.html:5
214
-#: searx/templates/legacy/index.html:8 searx/templates/legacy/index.html:12
215
-#: searx/templates/oscar/navbar.html:12
216
-#: searx/templates/oscar/preferences.html:3
217
-#: searx/templates/pix-art/index.html:8
218
-msgid "preferences"
219
-msgstr "Einstellungen"
220
-
221
-#: searx/templates/courgette/index.html:11
222
-#: searx/templates/legacy/index.html:10 searx/templates/oscar/about.html:2
223
-#: searx/templates/oscar/navbar.html:11 searx/templates/pix-art/index.html:7
224
-msgid "about"
225
-msgstr "Über uns"
226
-
227
-#: searx/templates/courgette/preferences.html:5
228
-#: searx/templates/legacy/preferences.html:5
229
-#: searx/templates/oscar/preferences.html:7
230
-#: searx/templates/pix-art/preferences.html:5
231
-msgid "Preferences"
232
-msgstr "Einstellungen"
233
-
234
-#: searx/templates/courgette/preferences.html:9
235
-#: searx/templates/legacy/preferences.html:9
236
-#: searx/templates/oscar/preferences.html:32
237
-#: searx/templates/oscar/preferences.html:34
238
-msgid "Default categories"
239
-msgstr "Standardkategorien"
240
-
241
-#: searx/templates/courgette/preferences.html:13
242
-#: searx/templates/legacy/preferences.html:14
243
-#: searx/templates/oscar/preferences.html:40
244
-#: searx/templates/pix-art/preferences.html:9
245
-msgid "Search language"
246
-msgstr "Suchsprache"
247
-
248
-#: searx/templates/courgette/preferences.html:16
249
-#: searx/templates/legacy/preferences.html:17
250
-#: searx/templates/oscar/languages.html:6
251
-#: searx/templates/pix-art/preferences.html:12
252
-msgid "Default language"
253
-msgstr "Standardsprache"
254
-
255
-#: searx/templates/courgette/preferences.html:24
256
-#: searx/templates/legacy/preferences.html:25
257
-#: searx/templates/oscar/preferences.html:46
258
-#: searx/templates/pix-art/preferences.html:20
259
-msgid "Interface language"
260
-msgstr "Sprache der Benutzeroberfläche"
261
-
262
-#: searx/templates/courgette/preferences.html:34
263
-#: searx/templates/legacy/preferences.html:35
264
-#: searx/templates/oscar/preferences.html:56
265
-msgid "Autocomplete"
266
-msgstr "Autovervollständigen"
267
-
268
-#: searx/templates/courgette/preferences.html:45
269
-#: searx/templates/legacy/preferences.html:46
270
-#: searx/templates/oscar/preferences.html:67
271
-msgid "Image proxy"
272
-msgstr "Proxy-Server für Bilder"
273
-
274
-#: searx/templates/courgette/preferences.html:48
275
-#: searx/templates/legacy/preferences.html:49
276
-#: searx/templates/oscar/preferences.html:71
277
-msgid "Enabled"
278
-msgstr "Aktiviert"
279
-
280
-#: searx/templates/courgette/preferences.html:49
281
-#: searx/templates/legacy/preferences.html:50
282
-#: searx/templates/oscar/preferences.html:72
283
-msgid "Disabled"
284
-msgstr "Deaktiviert"
285
-
286
-#: searx/templates/courgette/preferences.html:54
287
-#: searx/templates/legacy/preferences.html:55
288
-#: searx/templates/oscar/preferences.html:76
289
-#: searx/templates/pix-art/preferences.html:30
290
-msgid "Method"
291
-msgstr "Methode"
292
-
293
-#: searx/templates/courgette/preferences.html:63
294
-#: searx/templates/legacy/preferences.html:64
295
-#: searx/templates/oscar/preferences.html:85
296
-#: searx/templates/oscar/preferences.html:152
297
-#: searx/templates/oscar/preferences.html:159
298
-msgid "SafeSearch"
299
-msgstr "SafeSearch"
300
-
301
-#: searx/templates/courgette/preferences.html:66
302
-#: searx/templates/legacy/preferences.html:67
303
-#: searx/templates/oscar/preferences.html:89
304
-msgid "Strict"
305
-msgstr "Streng"
306
-
307
-#: searx/templates/courgette/preferences.html:67
308
-#: searx/templates/legacy/preferences.html:68
309
-#: searx/templates/oscar/preferences.html:90
310
-msgid "Moderate"
311
-msgstr "Moderat"
312
-
313
-#: searx/templates/courgette/preferences.html:68
314
-#: searx/templates/legacy/preferences.html:69
315
-#: searx/templates/oscar/preferences.html:91
316
-msgid "None"
317
-msgstr "Keine"
318
-
319
-#: searx/templates/courgette/preferences.html:73
320
-#: searx/templates/legacy/preferences.html:74
321
-#: searx/templates/oscar/preferences.html:95
322
-#: searx/templates/pix-art/preferences.html:39
323
-msgid "Themes"
324
-msgstr "Oberflächen"
325
-
326
-#: searx/templates/courgette/preferences.html:83
327
-msgid "Color"
328
-msgstr "Farbe"
329
-
330
-#: searx/templates/courgette/preferences.html:86
331
-msgid "Blue (default)"
332
-msgstr "Blau (Standard)"
333
-
334
-#: searx/templates/courgette/preferences.html:87
335
-msgid "Violet"
336
-msgstr "Violett"
337
-
338
-#: searx/templates/courgette/preferences.html:88
339
-msgid "Green"
340
-msgstr "Grün"
341
-
342
-#: searx/templates/courgette/preferences.html:89
343
-msgid "Cyan"
344
-msgstr "Türkis"
345
-
346
-#: searx/templates/courgette/preferences.html:90
347
-msgid "Orange"
348
-msgstr "Orange"
349
-
350
-#: searx/templates/courgette/preferences.html:91
351
-msgid "Red"
352
-msgstr "Rot"
353
-
354
-#: searx/templates/courgette/preferences.html:96
355
-#: searx/templates/legacy/preferences.html:93
356
-#: searx/templates/pix-art/preferences.html:49
357
-msgid "Currently used search engines"
358
-msgstr "Momentan genutzte Suchmaschinen"
359
-
360
-#: searx/templates/courgette/preferences.html:100
361
-#: searx/templates/legacy/preferences.html:97
362
-#: searx/templates/oscar/preferences.html:149
363
-#: searx/templates/oscar/preferences.html:162
364
-#: searx/templates/pix-art/preferences.html:53
365
-msgid "Engine name"
366
-msgstr "Suchmaschinen-Name"
367
-
368
-#: searx/templates/courgette/preferences.html:101
369
-#: searx/templates/legacy/preferences.html:98
370
-msgid "Category"
371
-msgstr "Kategorie"
372
-
373
-#: searx/templates/courgette/preferences.html:102
374
-#: searx/templates/courgette/preferences.html:113
375
-#: searx/templates/legacy/preferences.html:99
376
-#: searx/templates/legacy/preferences.html:110
377
-#: searx/templates/oscar/preferences.html:148
378
-#: searx/templates/oscar/preferences.html:163
379
-#: searx/templates/pix-art/preferences.html:54
380
-#: searx/templates/pix-art/preferences.html:64
381
-msgid "Allow"
382
-msgstr "Zulassen"
383
-
384
-#: searx/templates/courgette/preferences.html:102
385
-#: searx/templates/courgette/preferences.html:114
386
-#: searx/templates/legacy/preferences.html:99
387
-#: searx/templates/legacy/preferences.html:111
388
-#: searx/templates/pix-art/preferences.html:54
389
-#: searx/templates/pix-art/preferences.html:65
390
-msgid "Block"
391
-msgstr "Blockieren"
392
-
393
-#: searx/templates/courgette/preferences.html:122
394
-#: searx/templates/legacy/preferences.html:119
395
-#: searx/templates/oscar/preferences.html:282
396
-#: searx/templates/pix-art/preferences.html:73
397
-msgid ""
398
-"These settings are stored in your cookies, this allows us not to store this "
399
-"data about you."
400
-msgstr "Diese Einstellungen werden in Ihren Cookies gespeichert, deshalb müssen wir diese persönlichen Daten nicht bei uns speichern."
401
-
402
-#: searx/templates/courgette/preferences.html:124
403
-#: searx/templates/legacy/preferences.html:121
404
-#: searx/templates/oscar/preferences.html:284
405
-#: searx/templates/pix-art/preferences.html:75
406
-msgid ""
407
-"These cookies serve your sole convenience, we don't use these cookies to "
408
-"track you."
409
-msgstr "Diese Cookies ermöglichen lediglich eine komfortablere Nutzung, wir verwenden diese Cookies nicht, um Sie zu tracken."
410
-
411
-#: searx/templates/courgette/preferences.html:127
412
-#: searx/templates/legacy/preferences.html:124
413
-#: searx/templates/oscar/preferences.html:287
414
-#: searx/templates/pix-art/preferences.html:78
415
-msgid "save"
416
-msgstr "speichern"
417
-
418
-#: searx/templates/courgette/preferences.html:128
419
-#: searx/templates/legacy/preferences.html:125
420
-#: searx/templates/oscar/preferences.html:289
421
-msgid "Reset defaults"
422
-msgstr "Voreinstellungen wiederherstellen"
423
-
424
-#: searx/templates/courgette/preferences.html:129
425
-#: searx/templates/legacy/preferences.html:126
426
-#: searx/templates/oscar/preferences.html:288
427
-#: searx/templates/pix-art/preferences.html:79
428
-msgid "back"
429
-msgstr "zurück"
430
-
431
-#: searx/templates/courgette/results.html:12
432
-#: searx/templates/legacy/results.html:13
433
-#: searx/templates/oscar/results.html:124
434
-msgid "Search URL"
435
-msgstr "Such-URL"
436
-
437
-#: searx/templates/courgette/results.html:16
438
-#: searx/templates/legacy/results.html:17
439
-#: searx/templates/oscar/results.html:129
440
-msgid "Download results"
441
-msgstr "Suchergebnisse herunterladen"
442
-
443
-#: searx/templates/courgette/results.html:34
444
-#: searx/templates/legacy/results.html:35
445
-msgid "Answers"
446
-msgstr "Antworten"
447
-
448
-#: searx/templates/courgette/results.html:42
449
-#: searx/templates/legacy/results.html:43
450
-#: searx/templates/oscar/results.html:104
451
-msgid "Suggestions"
452
-msgstr "Vorschläge"
453
-
454
-#: searx/templates/courgette/results.html:70
455
-#: searx/templates/legacy/results.html:81
456
-#: searx/templates/oscar/results.html:53 searx/templates/oscar/results.html:66
457
-msgid "previous page"
458
-msgstr "vorherige Seite"
459
-
460
-#: searx/templates/courgette/results.html:81
461
-#: searx/templates/legacy/results.html:92
462
-#: searx/templates/oscar/results.html:45 searx/templates/oscar/results.html:75
463
-msgid "next page"
464
-msgstr "nächste Seite"
465
-
466
-#: searx/templates/courgette/search.html:3
467
-#: searx/templates/legacy/search.html:3 searx/templates/oscar/search.html:4
468
-#: searx/templates/oscar/search_full.html:9
469
-#: searx/templates/pix-art/search.html:3
470
-msgid "Search for..."
471
-msgstr "Suchen nach ..."
472
-
473
-#: searx/templates/courgette/stats.html:4 searx/templates/legacy/stats.html:4
474
-#: searx/templates/oscar/stats.html:5 searx/templates/pix-art/stats.html:4
475
-msgid "Engine stats"
476
-msgstr "Suchmaschinen-Statistiken"
477
-
478
-#: searx/templates/courgette/result_templates/images.html:4
479
-#: searx/templates/legacy/result_templates/images.html:4
480
-#: searx/templates/pix-art/result_templates/images.html:4
481
-msgid "original context"
482
-msgstr "Ursprünglicher Kontext"
483
-
484
-#: searx/templates/courgette/result_templates/torrent.html:7
485
-#: searx/templates/legacy/result_templates/torrent.html:11
486
-#: searx/templates/oscar/result_templates/torrent.html:6
487
-msgid "Seeder"
488
-msgstr "Seeder"
489
-
490
-#: searx/templates/courgette/result_templates/torrent.html:7
491
-#: searx/templates/legacy/result_templates/torrent.html:11
492
-#: searx/templates/oscar/result_templates/torrent.html:6
493
-msgid "Leecher"
494
-msgstr "Leecher"
495
-
496
-#: searx/templates/courgette/result_templates/torrent.html:9
497
-#: searx/templates/legacy/result_templates/torrent.html:9
498
-#: searx/templates/oscar/macros.html:24
499
-msgid "magnet link"
500
-msgstr "Magnet-Link"
501
-
502
-#: searx/templates/courgette/result_templates/torrent.html:10
503
-#: searx/templates/legacy/result_templates/torrent.html:10
504
-#: searx/templates/oscar/macros.html:25
505
-msgid "torrent file"
506
-msgstr "Torrent-Datei"
507
-
508
-#: searx/templates/legacy/categories.html:8
509
-msgid "Click on the magnifier to perform search"
510
-msgstr "Klicken Sie auf das Vergrößerungsglas, um die Suche zu starten"
511
-
512
-#: searx/templates/legacy/preferences.html:84
513
-#: searx/templates/oscar/preferences.html:112
514
-msgid "Results on new tabs"
515
-msgstr "Ergebnisse in neuen Tabs"
516
-
517
-#: searx/templates/legacy/preferences.html:87
518
-#: searx/templates/oscar/preferences.html:116
519
-msgid "On"
520
-msgstr "An"
521
-
522
-#: searx/templates/legacy/preferences.html:88
523
-#: searx/templates/oscar/preferences.html:117
524
-msgid "Off"
525
-msgstr "Aus"
526
-
527
-#: searx/templates/legacy/result_templates/code.html:3
528
-#: searx/templates/legacy/result_templates/default.html:3
529
-#: searx/templates/legacy/result_templates/map.html:9
530
-#: searx/templates/oscar/macros.html:35 searx/templates/oscar/macros.html:49
531
-msgid "cached"
532
-msgstr "im Cache"
533
-
534
-#: searx/templates/oscar/advanced.html:4
535
-msgid "Advanced settings"
536
-msgstr "Erweiterte Einstellungen"
537
-
538
-#: searx/templates/oscar/base.html:62
539
-#: searx/templates/oscar/messages/first_time.html:4
540
-#: searx/templates/oscar/messages/no_results.html:5
541
-#: searx/templates/oscar/messages/save_settings_successfull.html:5
542
-#: searx/templates/oscar/messages/unknow_error.html:5
543
-msgid "Close"
544
-msgstr "Schließen"
545
-
546
-#: searx/templates/oscar/base.html:64
547
-msgid "Error!"
548
-msgstr "Fehler!"
549
-
550
-#: searx/templates/oscar/base.html:90
551
-msgid "Powered by"
552
-msgstr "Bereitgestellt von"
553
-
554
-#: searx/templates/oscar/base.html:90
555
-msgid "a privacy-respecting, hackable metasearch engine"
556
-msgstr "eine die Privatsphäre respektierende, hackbare Meta-Suchmaschine"
557
-
558
-#: searx/templates/oscar/macros.html:37 searx/templates/oscar/macros.html:51
559
-msgid "proxied"
560
-msgstr "via Proxy-Server"
561
-
562
-#: searx/templates/oscar/preferences.html:12
563
-#: searx/templates/oscar/preferences.html:21
564
-msgid "General"
565
-msgstr "Allgemein"
566
-
567
-#: searx/templates/oscar/preferences.html:13
568
-#: searx/templates/oscar/preferences.html:133
569
-msgid "Engines"
570
-msgstr "Suchmaschinen"
571
-
572
-#: searx/templates/oscar/preferences.html:14
573
-#: searx/templates/oscar/preferences.html:204
574
-msgid "Plugins"
575
-msgstr "Plug-ins"
576
-
577
-#: searx/templates/oscar/preferences.html:15
578
-#: searx/templates/oscar/preferences.html:230
579
-msgid "Answerers"
580
-msgstr "Instant Answers/Sofortantworten"
581
-
582
-#: searx/templates/oscar/preferences.html:16
583
-#: searx/templates/oscar/preferences.html:257
584
-msgid "Cookies"
585
-msgstr "Cookies"
586
-
587
-#: searx/templates/oscar/preferences.html:41
588
-msgid "What language do you prefer for search?"
589
-msgstr "Welche Sprache möchten Sie für die Suche verwenden?"
590
-
591
-#: searx/templates/oscar/preferences.html:47
592
-msgid "Change the language of the layout"
593
-msgstr "Sprache des Layouts ändern"
594
-
595
-#: searx/templates/oscar/preferences.html:57
596
-msgid "Find stuff as you type"
597
-msgstr "Bereits während der Eingabe suchen"
598
-
599
-#: searx/templates/oscar/preferences.html:68
600
-msgid "Proxying image results through searx"
601
-msgstr "Bilder-Suchergebnisse über den searx-Proxy-Server laden"
602
-
603
-#: searx/templates/oscar/preferences.html:77
604
-msgid ""
605
-"Change how forms are submited, <a "
606
-"href=\"http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_methods\""
607
-" rel=\"external\">learn more about request methods</a>"
608
-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>"
609
-
610
-#: searx/templates/oscar/preferences.html:86
611
-msgid "Filter content"
612
-msgstr "Inhalte filtern"
613
-
614
-#: searx/templates/oscar/preferences.html:96
615
-msgid "Change searx layout"
616
-msgstr "searx-Layout ändern"
617
-
618
-#: searx/templates/oscar/preferences.html:105
619
-#: searx/templates/oscar/preferences.html:110
620
-msgid "Choose style for this theme"
621
-msgstr "Stilrichtung für diese Benutzeroberfläche auswählen"
622
-
623
-#: searx/templates/oscar/preferences.html:105
624
-#: searx/templates/oscar/preferences.html:110
625
-msgid "Style"
626
-msgstr "Stilrichtung"
627
-
628
-#: searx/templates/oscar/preferences.html:150
629
-#: searx/templates/oscar/preferences.html:161
630
-msgid "Shortcut"
631
-msgstr "Kürzel"
632
-
633
-#: searx/templates/oscar/preferences.html:151
634
-#: searx/templates/oscar/preferences.html:160
635
-msgid "Supports selected language"
636
-msgstr "Unterstützt die ausgewähle Sprache"
637
-
638
-#: searx/templates/oscar/preferences.html:153
639
-msgid "Time range"
640
-msgstr "Zeitraum"
641
-
642
-#: searx/templates/oscar/preferences.html:154
643
-#: searx/templates/oscar/preferences.html:158
644
-msgid "Avg. time"
645
-msgstr "Durchschn. Zeit"
646
-
647
-#: searx/templates/oscar/preferences.html:155
648
-#: searx/templates/oscar/preferences.html:157
649
-msgid "Max time"
650
-msgstr "Maximale Zeit"
651
-
652
-#: searx/templates/oscar/preferences.html:233
653
-msgid "This is the list of searx's instant answering modules."
654
-msgstr "Auflistung der searx-Module für Sofortantworten:"
655
-
656
-#: searx/templates/oscar/preferences.html:237
657
-msgid "Name"
658
-msgstr "Name"
659
-
660
-#: searx/templates/oscar/preferences.html:238
661
-msgid "Keywords"
662
-msgstr "Schlüsselwörter"
663
-
664
-#: searx/templates/oscar/preferences.html:239
665
-msgid "Description"
666
-msgstr "Beschreibung"
667
-
668
-#: searx/templates/oscar/preferences.html:240
669
-msgid "Examples"
670
-msgstr "Beispiele"
671
-
672
-#: searx/templates/oscar/preferences.html:260
673
-msgid ""
674
-"This is the list of cookies and their values searx is storing on your "
675
-"computer."
676
-msgstr "Hier werden die Cookies und die gespeicherten Cookie-Informationen aufgelistet, die searx auf Ihrem Computer speichert."
677
-
678
-#: searx/templates/oscar/preferences.html:261
679
-msgid "With that list, you can assess searx transparency."
680
-msgstr "Mit Hilfe dieser Auflistung können Sie die Transparenz der searx-Suche einschätzen."
681
-
682
-#: searx/templates/oscar/preferences.html:266
683
-msgid "Cookie name"
684
-msgstr "Cookie-Name"
685
-
686
-#: searx/templates/oscar/preferences.html:267
687
-msgid "Value"
688
-msgstr "Wert"
689
-
690
-#: searx/templates/oscar/results.html:7
691
-msgid "Search results"
692
-msgstr "Durchsuche Ergebnisse"
693
-
694
-#: searx/templates/oscar/results.html:119
695
-msgid "Links"
696
-msgstr "Links"
697
-
698
-#: searx/templates/oscar/search.html:6
699
-#: searx/templates/oscar/search_full.html:11
700
-msgid "Start search"
701
-msgstr "Suche starten"
702
-
703
-#: searx/templates/oscar/stats.html:2
704
-msgid "stats"
705
-msgstr "Statistiken"
706
-
707
-#: searx/templates/oscar/time-range.html:3
708
-msgid "Anytime"
709
-msgstr "Beliebiger Zeitunkt"
710
-
711
-#: searx/templates/oscar/time-range.html:6
712
-msgid "Last day"
713
-msgstr "Gestern"
714
-
715
-#: searx/templates/oscar/time-range.html:9
716
-msgid "Last week"
717
-msgstr "Letzte Woche"
718
-
719
-#: searx/templates/oscar/time-range.html:12
720
-msgid "Last month"
721
-msgstr "Letzter Monat"
722
-
723
-#: searx/templates/oscar/time-range.html:15
724
-msgid "Last year"
725
-msgstr "Letztes Jahr"
726
-
727
-#: searx/templates/oscar/messages/first_time.html:6
728
-#: searx/templates/oscar/messages/no_data_available.html:3
729
-msgid "Heads up!"
730
-msgstr "Aufgepasst!"
731
-
732
-#: searx/templates/oscar/messages/first_time.html:7
733
-msgid "It look like you are using searx first time."
734
-msgstr "Anscheinend benutzen Sie searx zum ersten Mal."
735
-
736
-#: searx/templates/oscar/messages/no_cookies.html:3
737
-msgid "Information!"
738
-msgstr "Zur Information!"
739
-
740
-#: searx/templates/oscar/messages/no_cookies.html:4
741
-msgid "currently, there are no cookies defined."
742
-msgstr "Zur Zeit sind keine Cookies definiert."
743
-
744
-#: searx/templates/oscar/messages/no_data_available.html:4
745
-msgid "There is currently no data available. "
746
-msgstr "Zur Zeit sind keine Daten verfügbar."
747
-
748
-#: searx/templates/oscar/messages/no_results.html:7
749
-msgid "Sorry!"
750
-msgstr "Entschuldigung!"
751
-
752
-#: searx/templates/oscar/messages/no_results.html:8
753
-msgid ""
754
-"we didn't find any results. Please use another query or search in more "
755
-"categories."
756
-msgstr "Leider konnten wir keine Suchergebnisse finden. Bitte verwenden Sie eine andere Suchabfrage oder erweitern Sie die Suche auf mehr Kategorien."
757
-
758
-#: searx/templates/oscar/messages/save_settings_successfull.html:7
759
-msgid "Well done!"
760
-msgstr "Gut gemacht!"
761
-
762
-#: searx/templates/oscar/messages/save_settings_successfull.html:8
763
-msgid "Settings saved successfully."
764
-msgstr "Einstellungen erfolgreich gespeichert."
765
-
766
-#: searx/templates/oscar/messages/unknow_error.html:7
767
-msgid "Oh snap!"
768
-msgstr "Hoppla!"
769
-
770
-#: searx/templates/oscar/messages/unknow_error.html:8
771
-msgid "Something went wrong."
772
-msgstr "Ein Fehler ist aufgetreten."
773
-
774
-#: searx/templates/oscar/result_templates/default.html:7
775
-msgid "show media"
776
-msgstr "Medien anzeigen"
777
-
778
-#: searx/templates/oscar/result_templates/default.html:7
779
-msgid "hide media"
780
-msgstr "Medien verbergen"
781
-
782
-#: searx/templates/oscar/result_templates/images.html:30
783
-msgid "Get image"
784
-msgstr "Bild herunterladen"
785
-
786
-#: searx/templates/oscar/result_templates/images.html:33
787
-msgid "View source"
788
-msgstr "Quelle anzeigen"
789
-
790
-#: searx/templates/oscar/result_templates/map.html:7
791
-msgid "show map"
792
-msgstr "Karte anzeigen"
793
-
794
-#: searx/templates/oscar/result_templates/map.html:7
795
-msgid "hide map"
796
-msgstr "Karte verbergen"
797
-
798
-#: searx/templates/oscar/result_templates/map.html:11
799
-msgid "show details"
800
-msgstr "Details anzeigen"
801
-
802
-#: searx/templates/oscar/result_templates/map.html:11
803
-msgid "hide details"
804
-msgstr "Details verbergen"
805
-
806
-#: searx/templates/oscar/result_templates/torrent.html:7
807
-msgid "Filesize"
808
-msgstr "Dateigröße"
809
-
810
-#: searx/templates/oscar/result_templates/torrent.html:9
811
-msgid "Bytes"
812
-msgstr "Bytes"
813
-
814
-#: searx/templates/oscar/result_templates/torrent.html:10
815
-msgid "kiB"
816
-msgstr "kiB"
817
-
818
-#: searx/templates/oscar/result_templates/torrent.html:11
819
-msgid "MiB"
820
-msgstr "MiB"
821
-
822
-#: searx/templates/oscar/result_templates/torrent.html:12
823
-msgid "GiB"
824
-msgstr "GiB"
825
-
826
-#: searx/templates/oscar/result_templates/torrent.html:13
827
-msgid "TiB"
828
-msgstr "TiB"
829
-
830
-#: searx/templates/oscar/result_templates/torrent.html:15
831
-msgid "Number of Files"
832
-msgstr "Anzahl Dateien"
833
-
834
-#: searx/templates/oscar/result_templates/videos.html:7
835
-msgid "show video"
836
-msgstr "Video anzeigen"
837
-
838
-#: searx/templates/oscar/result_templates/videos.html:7
839
-msgid "hide video"
840
-msgstr "Video verbergen"
841
-
842
-#: searx/templates/pix-art/results.html:28
843
-msgid "Load more..."
844
-msgstr "Mehr anzeigen ..."

+ 18
- 0
searx/utils.py View File

@@ -1,4 +1,6 @@
1 1
 import csv
2
+import hashlib
3
+import hmac
2 4
 import os
3 5
 import re
4 6
 
@@ -290,6 +292,15 @@ def convert_str_to_int(number_str):
290 292
         return 0
291 293
 
292 294
 
295
+# convert a variable to integer or return 0 if it's not a number
296
+def int_or_zero(num):
297
+    if isinstance(num, list):
298
+        if len(num) < 1:
299
+            return 0
300
+        num = num[0]
301
+    return convert_str_to_int(num)
302
+
303
+
293 304
 def is_valid_lang(lang):
294 305
     is_abbr = (len(lang) == 2)
295 306
     if is_abbr:
@@ -312,3 +323,10 @@ def load_module(filename, module_dir):
312 323
     module = load_source(modname, filepath)
313 324
     module.name = modname
314 325
     return module
326
+
327
+
328
+def new_hmac(secret_key, url):
329
+    if sys.version_info[0] == 2:
330
+        return hmac.new(bytes(secret_key), url, hashlib.sha256).hexdigest()
331
+    else:
332
+        return hmac.new(bytes(secret_key, 'utf-8'), url, hashlib.sha256).hexdigest()

+ 6
- 4
searx/webapp.py View File

@@ -69,6 +69,7 @@ from searx.plugins import plugins
69 69
 from searx.preferences import Preferences, ValidationException
70 70
 from searx.answerers import answerers
71 71
 from searx.url_utils import urlencode, urlparse, urljoin
72
+from searx.utils import new_hmac
72 73
 
73 74
 # check if the pyopenssl package is installed.
74 75
 # It is needed for SSL connection without trouble, see #298
@@ -290,7 +291,7 @@ def image_proxify(url):
290 291
     if settings.get('result_proxy'):
291 292
         return proxify(url)
292 293
 
293
-    h = hmac.new(settings['server']['secret_key'], url.encode('utf-8'), hashlib.sha256).hexdigest()
294
+    h = new_hmac(settings['server']['secret_key'], url.encode('utf-8'))
294 295
 
295 296
     return '{0}?{1}'.format(url_for('image_proxy'),
296 297
                             urlencode(dict(url=url.encode('utf-8'), h=h)))
@@ -704,7 +705,7 @@ def image_proxy():
704 705
     if not url:
705 706
         return '', 400
706 707
 
707
-    h = hmac.new(settings['server']['secret_key'], url, hashlib.sha256).hexdigest()
708
+    h = new_hmac(settings['server']['secret_key'], url)
708 709
 
709 710
     if h != request.args.get('h'):
710 711
         return '', 400
@@ -731,7 +732,7 @@ def image_proxy():
731 732
         logger.debug('image-proxy: wrong content-type: {0}'.format(resp.headers.get('content-type')))
732 733
         return '', 400
733 734
 
734
-    img = ''
735
+    img = b''
735 736
     chunk_counter = 0
736 737
 
737 738
     for chunk in resp.iter_content(1024 * 1024):
@@ -792,7 +793,8 @@ def opensearch():
792 793
 @app.route('/favicon.ico')
793 794
 def favicon():
794 795
     return send_from_directory(os.path.join(app.root_path,
795
-                                            'static/themes',
796
+                                            static_path,
797
+                                            'themes',
796 798
                                             get_current_theme_name(),
797 799
                                             'img'),
798 800
                                'favicon.png',

+ 91
- 0
tests/unit/engines/test_base.py View File

@@ -0,0 +1,91 @@
1
+# -*- coding: utf-8 -*-
2
+from collections import defaultdict
3
+import mock
4
+from searx.engines import base
5
+from searx.testing import SearxTestCase
6
+
7
+
8
+class TestBaseEngine(SearxTestCase):
9
+
10
+    def test_request(self):
11
+        query = 'test_query'
12
+        dicto = defaultdict(dict)
13
+        dicto['pageno'] = 1
14
+        params = base.request(query, dicto)
15
+        self.assertIn('url', params)
16
+        self.assertIn('base-search.net', params['url'])
17
+
18
+    def test_response(self):
19
+        self.assertRaises(AttributeError, base.response, None)
20
+        self.assertRaises(AttributeError, base.response, [])
21
+        self.assertRaises(AttributeError, base.response, '')
22
+        self.assertRaises(AttributeError, base.response, '[]')
23
+
24
+        response = mock.Mock(text='<response></response>')
25
+        self.assertEqual(base.response(response), [])
26
+
27
+        xml_mock = """<?xml version="1.0"?>
28
+<response>
29
+  <lst name="responseHeader">
30
+    <int name="status">0</int>
31
+    <int name="QTime">1</int>
32
+  </lst>
33
+  <result name="response" numFound="1" start="0">
34
+    <doc>
35
+      <date name="dchdate">2000-01-01T01:01:01Z</date>
36
+      <str name="dcdocid">1</str>
37
+      <str name="dccontinent">cna</str>
38
+      <str name="dccountry">us</str>
39
+      <str name="dccollection">ftciteseerx</str>
40
+      <str name="dcprovider">CiteSeerX</str>
41
+      <str name="dctitle">Science and more</str>
42
+      <arr name="dccreator">
43
+        <str>Someone</str>
44
+      </arr>
45
+      <arr name="dcperson">
46
+        <str>Someone</str>
47
+      </arr>
48
+      <arr name="dcsubject">
49
+        <str>Science and more</str>
50
+      </arr>
51
+      <str name="dcdescription">Science, and even more.</str>
52
+      <arr name="dccontributor">
53
+        <str>The neighbour</str>
54
+      </arr>
55
+      <str name="dcdate">2001</str>
56
+      <int name="dcyear">2001</int>
57
+      <arr name="dctype">
58
+        <str>text</str>
59
+      </arr>
60
+      <arr name="dctypenorm">
61
+        <str>1</str>
62
+      </arr>
63
+      <arr name="dcformat">
64
+        <str>application/pdf</str>
65
+      </arr>
66
+      <arr name="dccontenttype">
67
+        <str>application/pdf</str>
68
+      </arr>
69
+      <arr name="dcidentifier">
70
+        <str>http://example.org/</str>
71
+      </arr>
72
+      <str name="dclink">http://example.org</str>
73
+      <str name="dcsource">http://example.org</str>
74
+      <arr name="dclanguage">
75
+        <str>en</str>
76
+      </arr>
77
+      <str name="dcrights">Under the example.org licence</str>
78
+      <int name="dcoa">1</int>
79
+      <arr name="dclang">
80
+        <str>eng</str>
81
+      </arr>
82
+    </doc>
83
+  </result>
84
+</response>"""
85
+
86
+        response = mock.Mock(text=xml_mock.encode('utf-8'))
87
+        results = base.response(response)
88
+        self.assertEqual(type(results), list)
89
+        self.assertEqual(len(results), 1)
90
+        self.assertEqual(results[0]['title'], 'Science and more')
91
+        self.assertEqual(results[0]['content'], 'Science, and even more.')

+ 38
- 4
tests/unit/engines/test_bing_images.py View File

@@ -8,10 +8,12 @@ from searx.testing import SearxTestCase
8 8
 class TestBingImagesEngine(SearxTestCase):
9 9
 
10 10
     def test_request(self):
11
+        bing_images.supported_languages = ['fr-FR', 'en-US']
12
+
11 13
         query = 'test_query'
12 14
         dicto = defaultdict(dict)
13 15
         dicto['pageno'] = 1
14
-        dicto['language'] = 'fr_FR'
16
+        dicto['language'] = 'fr-FR'
15 17
         dicto['safesearch'] = 1
16 18
         dicto['time_range'] = ''
17 19
         params = bing_images.request(query, dicto)
@@ -19,12 +21,19 @@ class TestBingImagesEngine(SearxTestCase):
19 21
         self.assertTrue(query in params['url'])
20 22
         self.assertTrue('bing.com' in params['url'])
21 23
         self.assertTrue('SRCHHPGUSR' in params['cookies'])
22
-        self.assertTrue('fr' in params['cookies']['SRCHHPGUSR'])
24
+        self.assertTrue('DEMOTE' in params['cookies']['SRCHHPGUSR'])
25
+        self.assertTrue('_EDGE_S' in params['cookies'])
26
+        self.assertTrue('fr-fr' in params['cookies']['_EDGE_S'])
27
+
28
+        dicto['language'] = 'fr'
29
+        params = bing_images.request(query, dicto)
30
+        self.assertTrue('_EDGE_S' in params['cookies'])
31
+        self.assertTrue('fr-fr' in params['cookies']['_EDGE_S'])
23 32
 
24 33
         dicto['language'] = 'all'
25 34
         params = bing_images.request(query, dicto)
26
-        self.assertIn('SRCHHPGUSR', params['cookies'])
27
-        self.assertIn('en', params['cookies']['SRCHHPGUSR'])
35
+        self.assertTrue('_EDGE_S' in params['cookies'])
36
+        self.assertTrue('en-us' in params['cookies']['_EDGE_S'])
28 37
 
29 38
     def test_response(self):
30 39
         self.assertRaises(AttributeError, bing_images.response, None)
@@ -82,3 +91,28 @@ class TestBingImagesEngine(SearxTestCase):
82 91
         self.assertEqual(results[0]['content'], '')
83 92
         self.assertEqual(results[0]['thumbnail_src'], 'thumb_url')
84 93
         self.assertEqual(results[0]['img_src'], 'img_url')
94
+
95
+    def test_fetch_supported_languages(self):
96
+        html = """
97
+        <div>
98
+            <div id="region-section-content">
99
+                <ul class="b_vList">
100
+                    <li>
101
+                        <a href="https://bing...&setmkt=de-DE&s...">Germany</a>
102
+                        <a href="https://bing...&setmkt=nb-NO&s...">Norway</a>
103
+                    </li>
104
+                </ul>
105
+                <ul class="b_vList">
106
+                    <li>
107
+                        <a href="https://bing...&setmkt=es-AR&s...">Argentina</a>
108
+                    </li>
109
+                </ul>
110
+            </div>
111
+        </div>
112
+        """
113
+        response = mock.Mock(text=html)
114
+        languages = list(bing_images._fetch_supported_languages(response))
115
+        self.assertEqual(len(languages), 3)
116
+        self.assertIn('de-DE', languages)
117
+        self.assertIn('no-NO', languages)
118
+        self.assertIn('es-AR', languages)

+ 2
- 0
tests/unit/engines/test_bing_videos.py View File

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

+ 0
- 71
tests/unit/engines/test_blekko_images.py View File

@@ -1,71 +0,0 @@
1
-from collections import defaultdict
2
-import mock
3
-from searx.engines import blekko_images
4
-from searx.testing import SearxTestCase
5
-
6
-
7
-class TestBlekkoImagesEngine(SearxTestCase):
8
-
9
-    def test_request(self):
10
-        query = 'test_query'
11
-        dicto = defaultdict(dict)
12
-        dicto['pageno'] = 0
13
-        dicto['safesearch'] = 1
14
-        params = blekko_images.request(query, dicto)
15
-        self.assertIn('url', params)
16
-        self.assertIn(query, params['url'])
17
-        self.assertIn('blekko.com', params['url'])
18
-        self.assertIn('page', params['url'])
19
-
20
-        dicto['pageno'] = 1
21
-        params = blekko_images.request(query, dicto)
22
-        self.assertNotIn('page', params['url'])
23
-
24
-    def test_response(self):
25
-        self.assertRaises(AttributeError, blekko_images.response, None)
26
-        self.assertRaises(AttributeError, blekko_images.response, [])
27
-        self.assertRaises(AttributeError, blekko_images.response, '')
28
-        self.assertRaises(AttributeError, blekko_images.response, '[]')
29
-
30
-        response = mock.Mock(text='[]')
31
-        self.assertEqual(blekko_images.response(response), [])
32
-
33
-        json = """
34
-        [
35
-            {
36
-                "c": 1,
37
-                "page_url": "http://result_url.html",
38
-                "title": "Photo title",
39
-                "tn_url": "http://ts1.mm.bing.net/th?id=HN.608050619474382748&pid=15.1",
40
-                "url": "http://result_image.jpg"
41
-            },
42
-            {
43
-                "c": 2,
44
-                "page_url": "http://companyorange.simpsite.nl/OSM",
45
-                "title": "OSM",
46
-                "tn_url": "http://ts2.mm.bing.net/th?id=HN.608048068264919461&pid=15.1",
47
-                "url": "http://simpsite.nl/userdata2/58985/Home/OSM.bmp"
48
-            },
49
-            {
50
-                "c": 3,
51
-                "page_url": "http://invincible.webklik.nl/page/osm",
52
-                "title": "OSM",
53
-                "tn_url": "http://ts1.mm.bing.net/th?id=HN.608024514657649476&pid=15.1",
54
-                "url": "http://www.webklik.nl/user_files/2009_09/65324/osm.gif"
55
-            },
56
-            {
57
-                "c": 4,
58
-                "page_url": "http://www.offshorenorway.no/event/companyDetail/id/12492",
59
-                "title": "Go to OSM Offshore AS homepage",
60
-                "tn_url": "http://ts2.mm.bing.net/th?id=HN.608054265899847285&pid=15.1",
61
-                "url": "http://www.offshorenorway.no/firmalogo/OSM-logo.png"
62
-            }
63
-        ]
64
-        """
65
-        response = mock.Mock(text=json)
66
-        results = blekko_images.response(response)
67
-        self.assertEqual(type(results), list)
68
-        self.assertEqual(len(results), 4)
69
-        self.assertEqual(results[0]['title'], 'Photo title')
70
-        self.assertEqual(results[0]['url'], 'http://result_url.html')
71
-        self.assertEqual(results[0]['img_src'], 'http://result_image.jpg')

+ 2
- 5
tests/unit/engines/test_faroo.py View File

@@ -40,9 +40,6 @@ class TestFarooEngine(SearxTestCase):
40 40
         response = mock.Mock(text='{"data": []}')
41 41
         self.assertEqual(faroo.response(response), [])
42 42
 
43
-        response = mock.Mock(text='{"data": []}', status_code=401)
44
-        self.assertRaises(Exception, faroo.response, response)
45
-
46 43
         response = mock.Mock(text='{"data": []}', status_code=429)
47 44
         self.assertRaises(Exception, faroo.response, response)
48 45
 
@@ -98,14 +95,14 @@ class TestFarooEngine(SearxTestCase):
98 95
         response = mock.Mock(text=json)
99 96
         results = faroo.response(response)
100 97
         self.assertEqual(type(results), list)
101
-        self.assertEqual(len(results), 4)
98
+        self.assertEqual(len(results), 3)
102 99
         self.assertEqual(results[0]['title'], 'This is the title')
103 100
         self.assertEqual(results[0]['url'], 'http://this.is.the.url/')
104 101
         self.assertEqual(results[0]['content'], 'This is the content')
105 102
         self.assertEqual(results[1]['title'], 'This is the title2')
106 103
         self.assertEqual(results[1]['url'], 'http://this.is.the.url2/')
107 104
         self.assertEqual(results[1]['content'], 'This is the content2')
108
-        self.assertEqual(results[3]['img_src'], 'http://upload.wikimedia.org/optimized.jpg')
105
+        self.assertEqual(results[2]['thumbnail'], 'http://upload.wikimedia.org/optimized.jpg')
109 106
 
110 107
         json = """
111 108
         {}

+ 56
- 6
tests/unit/engines/test_google_news.py
File diff suppressed because it is too large
View File


+ 91
- 33
tests/unit/engines/test_nyaa.py View File

@@ -13,38 +13,92 @@ class TestNyaaEngine(SearxTestCase):
13 13
         params = nyaa.request(query, dic)
14 14
         self.assertTrue('url' in params)
15 15
         self.assertTrue(query in params['url'])
16
-        self.assertTrue('nyaa.se' in params['url'])
16
+        self.assertTrue('nyaa.si' in params['url'])
17 17
 
18 18
     def test_response(self):
19 19
         resp = mock.Mock(text='<html></html>')
20 20
         self.assertEqual(nyaa.response(resp), [])
21 21
 
22 22
         html = """
23
-        <table class="tlist">
24
-          <tbody>
25
-            <tr class="trusted tlistrow">
26
-              <td class="tlisticon">
27
-                <a href="//www.nyaa.se" title="English-translated Anime">
28
-                   <img src="//files.nyaa.se" alt="English-translated Anime">
29
-                </a>
30
-              </td>
31
-              <td class="tlistname">
32
-                <a href="//www.nyaa.se/?page3">
33
-                  Sample torrent title
34
-                </a>
35
-              </td>
36
-              <td class="tlistdownload">
37
-                <a href="//www.nyaa.se/?page_dl" title="Download">
38
-                  <img src="//files.nyaa.se/www-dl.png" alt="DL">
39
-                </a>
40
-              </td>
41
-              <td class="tlistsize">10 MiB</td>
42
-              <td class="tlistsn">1</td>
43
-              <td class="tlistln">3</td>
44
-              <td class="tlistdn">666</td>
45
-              <td class="tlistmn">0</td>
46
-            </tr>
47
-          </tbody>
23
+        <table class="table table-bordered table-hover table-striped torrent-list">
24
+        <thead>
25
+        <tr>
26
+        <th class="hdr-category text-center" style="width:80px;">
27
+        <div>Category</div>
28
+        </th>
29
+        <th class="hdr-name" style="width:auto;">
30
+        <div>Name</div>
31
+        </th>
32
+        <th class="hdr-comments sorting text-center" title="Comments" style="width:50px;">
33
+        <a href="/?f=0&amp;c=0_0&amp;q=Death+Parade&amp;s=comments&amp;o=desc"></a>
34
+        <i class="fa fa-comments-o"></i>
35
+        </th>
36
+        <th class="hdr-link text-center" style="width:70px;">
37
+        <div>Link</div>
38
+        </th>
39
+        <th class="hdr-size sorting text-center" style="width:100px;">
40
+        <a href="/?f=0&amp;c=0_0&amp;q=Death+Parade&amp;s=size&amp;o=desc"></a>
41
+        <div>Size</div>
42
+        </th>
43
+        <th class="hdr-date sorting_desc text-center" title="In local time" style="width:140px;">
44
+        <a href="/?f=0&amp;c=0_0&amp;q=Death+Parade&amp;s=id&amp;o=asc"></a>
45
+        <div>Date</div>
46
+        </th>
47
+        <th class="hdr-seeders sorting text-center" title="Seeders" style="width:50px;">
48
+        <a href="/?f=0&amp;c=0_0&amp;q=Death+Parade&amp;s=seeders&amp;o=desc"></a>
49
+        <i class="fa fa-arrow-up" aria-hidden="true"></i>
50
+        </th>
51
+        <th class="hdr-leechers sorting text-center" title="Leechers" style="width:50px;">
52
+        <a href="/?f=0&amp;c=0_0&amp;q=Death+Parade&amp;s=leechers&amp;o=desc"></a>
53
+        <i class="fa fa-arrow-down" aria-hidden="true"></i>
54
+        </th>
55
+        <th class="hdr-downloads sorting text-center" title="Completed downloads" style="width:50px;">
56
+        <a href="/?f=0&amp;c=0_0&amp;q=Death+Parade&amp;s=downloads&amp;o=desc"></a>
57
+        <i class="fa fa-check" aria-hidden="true"></i>
58
+        </th>
59
+        </tr>
60
+        </thead>
61
+        <tbody>
62
+        <tr class="default">
63
+        <td style="padding:0 4px;">
64
+        <a href="/?c=1_2" title="Anime - English-translated">
65
+        <img src="/static/img/icons/nyaa/1_2.png" alt="Anime - English-translated">
66
+        </a>
67
+        </td>
68
+        <td colspan="2">
69
+        <a href="/view/1" title="Sample title 1">Sample title 1</a>
70
+        </td>
71
+        <td class="text-center" style="white-space: nowrap;">
72
+        <a href="/download/1.torrent"><i class="fa fa-fw fa-download"></i></a>
73
+        <a href="magnet:?xt=urn:btih:2"><i class="fa fa-fw fa-magnet"></i></a>
74
+        </td>
75
+        <td class="text-center">723.7 MiB</td>
76
+        <td class="text-center" data-timestamp="1503307456" title="1 week 3
77
+        days 9 hours 44 minutes 39 seconds ago">2017-08-21 11:24</td>
78
+        <td class="text-center" style="color: green;">1</td>
79
+        <td class="text-center" style="color: red;">3</td>
80
+        <td class="text-center">12</td>
81
+        </tr>
82
+        <tr class="default">
83
+        <td style="padding:0 4px;">
84
+        <a href="/?c=1_2" title="Anime - English-translated">
85
+        <img src="/static/img/icons/nyaa/1_2.png" alt="Anime - English-translated">
86
+        </a>
87
+        </td>
88
+        <td colspan="2">
89
+        <a href="/view/2" title="Sample title 2">Sample title 2</a>
90
+        </td>
91
+        <td class="text-center" style="white-space: nowrap;">
92
+        <a href="magnet:?xt=urn:btih:2"><i class="fa fa-fw fa-magnet"></i></a>
93
+        </td>
94
+        <td class="text-center">8.2 GiB</td>
95
+        <td class="text-center" data-timestamp="1491608400" title="4 months 3
96
+        weeks 4 days 19 hours 28 minutes 55 seconds ago">2017-04-08 01:40</td>
97
+        <td class="text-center" style="color: green;">10</td>
98
+        <td class="text-center" style="color: red;">1</td>
99
+        <td class="text-center">206</td>
100
+        </tr>
101
+        </tbody>
48 102
         </table>
49 103
         """
50 104
 
@@ -52,15 +106,19 @@ class TestNyaaEngine(SearxTestCase):
52 106
         results = nyaa.response(resp)
53 107
 
54 108
         self.assertEqual(type(results), list)
55
-        self.assertEqual(len(results), 1)
109
+        self.assertEqual(len(results), 2)
56 110
 
57 111
         r = results[0]
58
-        self.assertTrue(r['url'].find('www.nyaa.se/?page3') >= 0)
59
-        self.assertTrue(r['torrentfile'].find('www.nyaa.se/?page_dl') >= 0)
60
-        self.assertTrue(r['content'].find('English-translated Anime') >= 0)
61
-        self.assertTrue(r['content'].find('Downloaded 666 times.') >= 0)
112
+        self.assertTrue(r['url'].find('1') >= 0)
113
+        self.assertTrue(r['torrentfile'].find('1.torrent') >= 0)
114
+        self.assertTrue(r['content'].find('Anime - English-translated') >= 0)
115
+        self.assertTrue(r['content'].find('Downloaded 12 times.') >= 0)
62 116
 
63
-        self.assertEqual(r['title'], 'Sample torrent title')
117
+        self.assertEqual(r['title'], 'Sample title 1')
64 118
         self.assertEqual(r['seed'], 1)
65 119
         self.assertEqual(r['leech'], 3)
66
-        self.assertEqual(r['filesize'], 10 * 1024 * 1024)
120
+        self.assertEqual(r['filesize'], 723700000)
121
+
122
+        r = results[1]
123
+        self.assertTrue(r['url'].find('2') >= 0)
124
+        self.assertTrue(r['magnetlink'].find('magnet:') >= 0)

+ 3
- 3
tests/unit/engines/test_swisscows.py View File

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

+ 14
- 18
tests/unit/engines/test_torrentz.py View File

@@ -14,7 +14,7 @@ class TestTorrentzEngine(SearxTestCase):
14 14
         params = torrentz.request(query, dic)
15 15
         self.assertTrue('url' in params)
16 16
         self.assertTrue(query in params['url'])
17
-        self.assertTrue('torrentz.eu' in params['url'])
17
+        self.assertTrue('torrentz2.eu' in params['url'])
18 18
 
19 19
     def test_response(self):
20 20
         resp = mock.Mock(text='<html></html>')
@@ -30,13 +30,11 @@ class TestTorrentzEngine(SearxTestCase):
30 30
               books ebooks
31 31
             </dt>
32 32
             <dd>
33
-              <span class="v">1</span>
34
-              <span class="a">
35
-                <span title="Sun, 22 Nov 2015 03:01:42">4 months</span>
36
-              </span>
37
-              <span class="s">30 MB</span>
38
-              <span class="u">14</span>
39
-              <span class="d">1</span>
33
+              <span>1</span>
34
+              <span title="1503595924">5 hours</span>
35
+              <span>30 MB</span>
36
+              <span>14</span>
37
+              <span>1</span>
40 38
             </dd>
41 39
           </dl>
42 40
 
@@ -48,13 +46,11 @@ class TestTorrentzEngine(SearxTestCase):
48 46
               books ebooks
49 47
             </dt>
50 48
             <dd>
51
-              <span class="v">1</span>
52
-              <span class="a">
53
-                <span title="Sun, 2124091j0j190gm42">4 months</span>
54
-              </span>
55
-              <span class="s">30MB</span>
56
-              <span class="u">5,555</span>
57
-              <span class="d">1,234,567</span>
49
+              <span>1</span>
50
+              <span title="1503595924 aaa">5 hours</span>
51
+              <span>30MB</span>
52
+              <span>5,555</span>
53
+              <span>1,234,567</span>
58 54
             </dd>
59 55
           </dl>
60 56
         </div>
@@ -68,10 +64,10 @@ class TestTorrentzEngine(SearxTestCase):
68 64
 
69 65
         # testing against the first result
70 66
         r = results[0]
71
-        self.assertEqual(r['url'], 'https://torrentz.eu/4362e08b1d80e1820fb2550b752f9f3126fe76d6')
67
+        self.assertEqual(r['url'], 'https://torrentz2.eu/4362e08b1d80e1820fb2550b752f9f3126fe76d6')
72 68
         self.assertEqual(r['title'], 'Completely valid info books ebooks')
73 69
         # 22 Nov 2015 03:01:42
74
-        self.assertEqual(r['publishedDate'], datetime(2015, 11, 22, 3, 1, 42))
70
+        self.assertEqual(r['publishedDate'], datetime.fromtimestamp(1503595924))
75 71
         self.assertEqual(r['seed'], 14)
76 72
         self.assertEqual(r['leech'], 1)
77 73
         self.assertEqual(r['filesize'], 30 * 1024 * 1024)
@@ -79,7 +75,7 @@ class TestTorrentzEngine(SearxTestCase):
79 75
 
80 76
         # testing against the second result
81 77
         r = results[1]
82
-        self.assertEqual(r['url'], 'https://torrentz.eu/poaskdpokaspod')
78
+        self.assertEqual(r['url'], 'https://torrentz2.eu/poaskdpokaspod')
83 79
         self.assertEqual(r['title'], 'Invalid hash and date and filesize books ebooks')
84 80
         self.assertEqual(r['seed'], 5555)
85 81
         self.assertEqual(r['leech'], 1234567)

+ 8
- 8
utils/fetch_languages.py View File

@@ -8,13 +8,13 @@
8 8
 # are written in current directory to avoid overwriting in case something goes wrong.
9 9
 
10 10
 from requests import get
11
-from urllib import urlencode
12 11
 from lxml.html import fromstring
13
-from json import loads, dumps
12
+from json import loads, dump
14 13
 import io
15 14
 from sys import path
16 15
 path.append('../searx')  # noqa
17 16
 from searx import settings
17
+from searx.url_utils import urlencode
18 18
 from searx.engines import initialize_engines, engines
19 19
 
20 20
 # Geonames API for country names.
@@ -70,7 +70,7 @@ def get_country_name(locale):
70 70
     json = loads(response.text)
71 71
     content = json.get('geonames', None)
72 72
     if content is None or len(content) != 1:
73
-        print "No country name found for " + locale[0] + "-" + locale[1]
73
+        print("No country name found for " + locale[0] + "-" + locale[1])
74 74
         return ''
75 75
 
76 76
     return content[0].get('countryName', '')
@@ -84,11 +84,11 @@ def fetch_supported_languages():
84 84
             try:
85 85
                 engines_languages[engine_name] = engines[engine_name].fetch_supported_languages()
86 86
             except Exception as e:
87
-                print e
87
+                print(e)
88 88
 
89 89
     # write json file
90 90
     with io.open(engines_languages_file, "w", encoding="utf-8") as f:
91
-        f.write(unicode(dumps(engines_languages, ensure_ascii=False, encoding="utf-8")))
91
+        dump(engines_languages, f, ensure_ascii=False)
92 92
 
93 93
 
94 94
 # Join all language lists.
@@ -97,7 +97,7 @@ def join_language_lists():
97 97
     global languages
98 98
     # include wikipedia first for more accurate language names
99 99
     languages = {code: lang for code, lang
100
-                 in engines_languages['wikipedia'].iteritems()
100
+                 in engines_languages['wikipedia'].items()
101 101
                  if valid_code(code)}
102 102
 
103 103
     for engine_name in engines_languages:
@@ -121,7 +121,7 @@ def join_language_lists():
121 121
     # filter list to include only languages supported by most engines
122 122
     min_supported_engines = int(0.70 * len(engines_languages))
123 123
     languages = {code: lang for code, lang
124
-                 in languages.iteritems()
124
+                 in languages.items()
125 125
                  if len(lang.get('counter', [])) >= min_supported_engines or
126 126
                  len(languages.get(code.split('-')[0], {}).get('counter', [])) >= min_supported_engines}
127 127
 
@@ -165,7 +165,7 @@ def filter_single_country_languages():
165 165
 
166 166
 # Write languages.py.
167 167
 def write_languages_file():
168
-    new_file = open(languages_file, 'w')
168
+    new_file = open(languages_file, 'wb')
169 169
     file_content = '# -*- coding: utf-8 -*-\n'\
170 170
                    + '# list of language codes\n'\
171 171
                    + '# this file is generated automatically by utils/update_search_languages.py\n'\

+ 3
- 3
utils/update-translations.sh View File

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