Browse Source

Merge branch 'master' into http1.1

Alexandre Flament 8 years ago
parent
commit
a88768efd8
87 changed files with 578 additions and 117 deletions
  1. 5 0
      .travis.yml
  2. 2 0
      AUTHORS.rst
  3. 2 2
      manage.sh
  4. 3 3
      requirements-dev.txt
  5. 1 1
      requirements.txt
  6. 9 3
      searx/engines/__init__.py
  7. 1 1
      searx/engines/digbt.py
  8. 11 35
      searx/engines/kickass.py
  9. 109 0
      searx/engines/pdbe.py
  10. 78 0
      searx/engines/seedpeer.py
  11. 26 1
      searx/settings.yml
  12. 3 3
      searx/settings_robot.yml
  13. 0 0
      searx/static/themes/legacy/css/style-rtl.css
  14. 0 0
      searx/static/themes/legacy/css/style.css
  15. 0 0
      searx/static/themes/legacy/img/favicon.png
  16. 0 0
      searx/static/themes/legacy/img/github_ribbon.png
  17. 0 0
      searx/static/themes/legacy/img/icons/icon_500px.ico
  18. 0 0
      searx/static/themes/legacy/img/icons/icon_bing.ico
  19. 0 0
      searx/static/themes/legacy/img/icons/icon_dailymotion.ico
  20. 0 0
      searx/static/themes/legacy/img/icons/icon_deezer.ico
  21. 0 0
      searx/static/themes/legacy/img/icons/icon_deviantart.ico
  22. 0 0
      searx/static/themes/legacy/img/icons/icon_digg.ico
  23. 0 0
      searx/static/themes/legacy/img/icons/icon_duckduckgo.ico
  24. 0 0
      searx/static/themes/legacy/img/icons/icon_flickr.ico
  25. 0 0
      searx/static/themes/legacy/img/icons/icon_github.ico
  26. 0 0
      searx/static/themes/legacy/img/icons/icon_google play apps.ico
  27. 0 0
      searx/static/themes/legacy/img/icons/icon_google play movies.ico
  28. 0 0
      searx/static/themes/legacy/img/icons/icon_google play music.ico
  29. 0 0
      searx/static/themes/legacy/img/icons/icon_google.ico
  30. 0 0
      searx/static/themes/legacy/img/icons/icon_kickass.ico
  31. 0 0
      searx/static/themes/legacy/img/icons/icon_openstreetmap.ico
  32. 0 0
      searx/static/themes/legacy/img/icons/icon_searchcode code.ico
  33. 0 0
      searx/static/themes/legacy/img/icons/icon_searchcode doc.ico
  34. 0 0
      searx/static/themes/legacy/img/icons/icon_searchcode.ico
  35. 0 0
      searx/static/themes/legacy/img/icons/icon_soundcloud.ico
  36. 0 0
      searx/static/themes/legacy/img/icons/icon_stackoverflow.ico
  37. 0 0
      searx/static/themes/legacy/img/icons/icon_startpage.ico
  38. 0 0
      searx/static/themes/legacy/img/icons/icon_subtitleseeker.ico
  39. 0 0
      searx/static/themes/legacy/img/icons/icon_twitter.ico
  40. 0 0
      searx/static/themes/legacy/img/icons/icon_vimeo.ico
  41. 0 0
      searx/static/themes/legacy/img/icons/icon_wikipedia.ico
  42. 0 0
      searx/static/themes/legacy/img/icons/icon_yahoo.ico
  43. 0 0
      searx/static/themes/legacy/img/icons/icon_youtube.ico
  44. 0 0
      searx/static/themes/legacy/img/preference-icon.png
  45. 0 0
      searx/static/themes/legacy/img/search-icon.png
  46. 0 0
      searx/static/themes/legacy/img/searx.png
  47. 0 0
      searx/static/themes/legacy/img/searx_logo.svg
  48. 0 0
      searx/static/themes/legacy/js/searx.js
  49. 0 0
      searx/static/themes/legacy/less/autocompleter.less
  50. 0 0
      searx/static/themes/legacy/less/code.less
  51. 0 0
      searx/static/themes/legacy/less/definitions.less
  52. 0 0
      searx/static/themes/legacy/less/mixins.less
  53. 0 0
      searx/static/themes/legacy/less/search.less
  54. 0 0
      searx/static/themes/legacy/less/style-rtl.less
  55. 0 0
      searx/static/themes/legacy/less/style.less
  56. 1 1
      searx/templates/courgette/base.html
  57. 1 1
      searx/templates/legacy/404.html
  58. 2 2
      searx/templates/legacy/about.html
  59. 1 1
      searx/templates/legacy/base.html
  60. 0 0
      searx/templates/legacy/categories.html
  61. 0 0
      searx/templates/legacy/github_ribbon.html
  62. 3 3
      searx/templates/legacy/index.html
  63. 0 0
      searx/templates/legacy/infobox.html
  64. 0 0
      searx/templates/legacy/opensearch.xml
  65. 0 0
      searx/templates/legacy/opensearch_response_rss.xml
  66. 2 2
      searx/templates/legacy/preferences.html
  67. 0 0
      searx/templates/legacy/result_templates/code.html
  68. 0 0
      searx/templates/legacy/result_templates/default.html
  69. 0 0
      searx/templates/legacy/result_templates/images.html
  70. 0 0
      searx/templates/legacy/result_templates/map.html
  71. 0 0
      searx/templates/legacy/result_templates/torrent.html
  72. 0 0
      searx/templates/legacy/result_templates/videos.html
  73. 5 5
      searx/templates/legacy/results.html
  74. 1 1
      searx/templates/legacy/search.html
  75. 1 1
      searx/templates/legacy/stats.html
  76. 6 0
      searx/templates/oscar/macros.html
  77. 1 1
      searx/templates/pix-art/preferences.html
  78. 1 1
      searx/templates/pix-art/stats.html
  79. 15 0
      searx/utils.py
  80. 22 5
      searx/webapp.py
  81. 24 28
      tests/robot/test_basic.robot
  82. 64 0
      tests/unit/engines/seedpeer_fixture.html
  83. 3 1
      tests/unit/engines/test_digbt.py
  84. 13 13
      tests/unit/engines/test_kickass.py
  85. 109 0
      tests/unit/engines/test_pdbe.py
  86. 51 0
      tests/unit/engines/test_seedpeer.py
  87. 2 2
      tests/unit/test_webapp.py

+ 5 - 0
.travis.yml

@@ -4,6 +4,8 @@ cache:
   - npm
   - npm
   - directories:
   - directories:
     - $HOME/.cache/pip
     - $HOME/.cache/pip
+addons:
+  firefox: "latest"
 language: python
 language: python
 python:
 python:
   - "2.7"
   - "2.7"
@@ -12,6 +14,9 @@ before_install:
   - "sh -e /etc/init.d/xvfb start"
   - "sh -e /etc/init.d/xvfb start"
   - npm install less grunt-cli
   - npm install less grunt-cli
   - ( cd searx/static/themes/oscar;npm install; cd - )
   - ( cd searx/static/themes/oscar;npm install; cd - )
+  - mkdir -p ~/drivers; export PATH=~/drivers:$PATH;
+  - GECKODRIVER_URL="https://github.com/mozilla/geckodriver/releases/download/v0.11.1/geckodriver-v0.11.1-linux64.tar.gz";
+  - FILE=`mktemp`; wget "$GECKODRIVER_URL" -qO $FILE && tar xz -C ~/drivers -f $FILE geckodriver; rm $FILE; chmod 777 ~/drivers/geckodriver;
 install:
 install:
   - ./manage.sh update_dev_packages
   - ./manage.sh update_dev_packages
   - pip install coveralls
   - pip install coveralls

+ 2 - 0
AUTHORS.rst

@@ -58,3 +58,5 @@ generally made searx better:
 - marc @a01200356
 - marc @a01200356
 - Harry Wood @harry-wood
 - Harry Wood @harry-wood
 - Thomas Renard @threnard
 - Thomas Renard @threnard
+- Pydo `<https://github.com/pydo>`_
+- Athemis `<https://github.com/Athemis>`_

+ 2 - 2
manage.sh

@@ -53,8 +53,8 @@ build_style() {
 
 
 styles() {
 styles() {
     echo '[!] Building styles'
     echo '[!] Building styles'
-	build_style themes/default/less/style.less themes/default/css/style.css
-	build_style themes/default/less/style-rtl.less themes/default/css/style-rtl.css
+	build_style themes/legacy/less/style.less themes/legacy/css/style.css
+	build_style themes/legacy/less/style-rtl.less themes/legacy/css/style-rtl.css
 	build_style themes/courgette/less/style.less themes/courgette/css/style.css
 	build_style themes/courgette/less/style.less themes/courgette/css/style.css
 	build_style themes/courgette/less/style-rtl.less themes/courgette/css/style-rtl.css
 	build_style themes/courgette/less/style-rtl.less themes/courgette/css/style-rtl.css
 	build_style less/bootstrap/bootstrap.less css/bootstrap.min.css
 	build_style less/bootstrap/bootstrap.less css/bootstrap.min.css

+ 3 - 3
requirements-dev.txt

@@ -3,8 +3,8 @@ mock==2.0.0
 nose2[coverage-plugin]
 nose2[coverage-plugin]
 pep8==1.7.0
 pep8==1.7.0
 plone.testing==5.0.0
 plone.testing==5.0.0
-robotframework-selenium2library==1.7.4
+robotframework-selenium2library==1.8.0
 robotsuite==1.7.0
 robotsuite==1.7.0
-transifex-client==0.11
+transifex-client==0.12.2
 unittest2==1.1.0
 unittest2==1.1.0
-zope.testrunner==4.4.10
+zope.testrunner==4.5.1

+ 1 - 1
requirements.txt

@@ -1,4 +1,4 @@
-certifi==2016.2.28
+certifi==2016.9.26
 flask==0.11.1
 flask==0.11.1
 flask-babel==0.11.1
 flask-babel==0.11.1
 lxml==3.6.0
 lxml==3.6.0

+ 9 - 3
searx/engines/__init__.py

@@ -57,11 +57,17 @@ def load_module(filename):
 
 
 
 
 def load_engine(engine_data):
 def load_engine(engine_data):
-    engine_name = engine_data['engine']
+
+    if '_' in engine_data['name']:
+        logger.error('Engine name conains underscore: "{}"'.format(engine_data['name']))
+        sys.exit(1)
+
+    engine_module = engine_data['engine']
+
     try:
     try:
-        engine = load_module(engine_name + '.py')
+        engine = load_module(engine_module + '.py')
     except:
     except:
-        logger.exception('Cannot load engine "{}"'.format(engine_name))
+        logger.exception('Cannot load engine "{}"'.format(engine_module))
         return None
         return None
 
 
     for param_name in engine_data:
     for param_name in engine_data:

+ 1 - 1
searx/engines/digbt.py

@@ -40,7 +40,7 @@ def response(resp):
     results = list()
     results = list()
     for result in search_res:
     for result in search_res:
         url = urljoin(URL, result.xpath('.//a[@title]/@href')[0])
         url = urljoin(URL, result.xpath('.//a[@title]/@href')[0])
-        title = result.xpath('.//a[@title]/text()')[0]
+        title = extract_text(result.xpath('.//a[@title]'))
         content = extract_text(result.xpath('.//div[@class="files"]'))
         content = extract_text(result.xpath('.//div[@class="files"]'))
         files_data = extract_text(result.xpath('.//div[@class="tail"]')).split()
         files_data = extract_text(result.xpath('.//div[@class="tail"]')).split()
         filesize = get_torrent_size(files_data[FILESIZE], files_data[FILESIZE_MULTIPLIER])
         filesize = get_torrent_size(files_data[FILESIZE], files_data[FILESIZE_MULTIPLIER])

+ 11 - 35
searx/engines/kickass.py

@@ -16,13 +16,14 @@ from urllib import quote
 from lxml import html
 from lxml import html
 from operator import itemgetter
 from operator import itemgetter
 from searx.engines.xpath import extract_text
 from searx.engines.xpath import extract_text
+from searx.utils import get_torrent_size, convert_str_to_int
 
 
 # engine dependent config
 # engine dependent config
 categories = ['videos', 'music', 'files']
 categories = ['videos', 'music', 'files']
 paging = True
 paging = True
 
 
 # search-url
 # search-url
-url = 'https://kickass.to/'
+url = 'https://kickass.cd/'
 search_url = url + 'search/{search_term}/{pageno}/'
 search_url = url + 'search/{search_term}/{pageno}/'
 
 
 # specific xpath variables
 # specific xpath variables
@@ -57,41 +58,16 @@ def response(resp):
         href = urljoin(url, link.attrib['href'])
         href = urljoin(url, link.attrib['href'])
         title = extract_text(link)
         title = extract_text(link)
         content = escape(extract_text(result.xpath(content_xpath)))
         content = escape(extract_text(result.xpath(content_xpath)))
-        seed = result.xpath('.//td[contains(@class, "green")]/text()')[0]
-        leech = result.xpath('.//td[contains(@class, "red")]/text()')[0]
-        filesize = result.xpath('.//td[contains(@class, "nobr")]/text()')[0]
-        filesize_multiplier = result.xpath('.//td[contains(@class, "nobr")]//span/text()')[0]
-        files = result.xpath('.//td[contains(@class, "center")][2]/text()')[0]
-
-        # convert seed to int if possible
-        if seed.isdigit():
-            seed = int(seed)
-        else:
-            seed = 0
+        seed = extract_text(result.xpath('.//td[contains(@class, "green")]'))
+        leech = extract_text(result.xpath('.//td[contains(@class, "red")]'))
+        filesize_info = extract_text(result.xpath('.//td[contains(@class, "nobr")]'))
+        files = extract_text(result.xpath('.//td[contains(@class, "center")][2]'))
 
 
-        # convert leech to int if possible
-        if leech.isdigit():
-            leech = int(leech)
-        else:
-            leech = 0
-
-        # convert filesize to byte if possible
-        try:
-            filesize = float(filesize)
-
-            # convert filesize to byte
-            if filesize_multiplier == 'TB':
-                filesize = int(filesize * 1024 * 1024 * 1024 * 1024)
-            elif filesize_multiplier == 'GB':
-                filesize = int(filesize * 1024 * 1024 * 1024)
-            elif filesize_multiplier == 'MB':
-                filesize = int(filesize * 1024 * 1024)
-            elif filesize_multiplier == 'KB':
-                filesize = int(filesize * 1024)
-        except:
-            filesize = None
-
-        # convert files to int if possible
+        seed = convert_str_to_int(seed)
+        leech = convert_str_to_int(leech)
+
+        filesize, filesize_multiplier = filesize_info.split()
+        filesize = get_torrent_size(filesize, filesize_multiplier)
         if files.isdigit():
         if files.isdigit():
             files = int(files)
             files = int(files)
         else:
         else:

+ 109 - 0
searx/engines/pdbe.py

@@ -0,0 +1,109 @@
+"""
+ PDBe (Protein Data Bank in Europe)
+
+ @website       https://www.ebi.ac.uk/pdbe
+ @provide-api   yes (https://www.ebi.ac.uk/pdbe/api/doc/search.html),
+                unlimited
+ @using-api     yes
+ @results       python dictionary (from json)
+ @stable        yes
+ @parse         url, title, content, img_src
+"""
+
+from json import loads
+from flask_babel import gettext
+
+categories = ['science']
+
+hide_obsolete = False
+
+# status codes of unpublished entries
+pdb_unpublished_codes = ['HPUB', 'HOLD', 'PROC', 'WAIT', 'AUTH', 'AUCO', 'REPL', 'POLC', 'REFI', 'TRSF', 'WDRN']
+# url for api query
+pdbe_solr_url = 'https://www.ebi.ac.uk/pdbe/search/pdb/select?'
+# base url for results
+pdbe_entry_url = 'https://www.ebi.ac.uk/pdbe/entry/pdb/{pdb_id}'
+# link to preview image of structure
+pdbe_preview_url = 'https://www.ebi.ac.uk/pdbe/static/entry/{pdb_id}_deposited_chain_front_image-200x200.png'
+
+
+def request(query, params):
+
+    params['url'] = pdbe_solr_url
+    params['method'] = 'POST'
+    params['data'] = {
+        'q': query,
+        'wt': "json"  # request response in parsable format
+    }
+    return params
+
+
+def construct_body(result):
+    # set title
+    title = result['title']
+
+    # construct content body
+    content = """{title}<br />{authors} {journal} <strong>{volume}</strong>&nbsp;{page} ({year})"""
+
+    # replace placeholders with actual content
+    try:
+        if result['journal']:
+            content = content.format(
+                title=result['citation_title'],
+                authors=result['entry_author_list'][0], journal=result['journal'], volume=result['journal_volume'],
+                page=result['journal_page'], year=result['citation_year'])
+        else:
+            content = content.format(
+                title=result['citation_title'],
+                authors=result['entry_author_list'][0], journal='', volume='', page='', year=result['release_year'])
+        img_src = pdbe_preview_url.format(pdb_id=result['pdb_id'])
+    except (KeyError):
+        content = None
+        img_src = None
+
+    # construct url for preview image
+    try:
+        img_src = pdbe_preview_url.format(pdb_id=result['pdb_id'])
+    except (KeyError):
+        img_src = None
+
+    return [title, content, img_src]
+
+
+def response(resp):
+
+    results = []
+    json = loads(resp.text)['response']['docs']
+
+    # parse results
+    for result in json:
+        # catch obsolete entries and mark them accordingly
+        if result['status'] in pdb_unpublished_codes:
+            continue
+        if hide_obsolete:
+            continue
+        if result['status'] == 'OBS':
+            # expand title to add some sort of warning message
+            title = gettext('{title}&nbsp;(OBSOLETE)').format(title=result['title'])
+            superseded_url = pdbe_entry_url.format(pdb_id=result['superseded_by'])
+
+            # since we can't construct a proper body from the response, we'll make up our own
+            msg_superseded = gettext("This entry has been superseded by")
+            content = '<em>{msg_superseded} \<a href="{url}">{pdb_id}</a></em>'.format(
+                msg_superseded=msg_superseded,
+                url=superseded_url,
+                pdb_id=result['superseded_by'], )
+
+            # obsoleted entries don't have preview images
+            img_src = None
+        else:
+            title, content, img_src = construct_body(result)
+
+        results.append({
+            'url': pdbe_entry_url.format(pdb_id=result['pdb_id']),
+            'title': title,
+            'content': content,
+            'img_src': img_src
+        })
+
+    return results

+ 78 - 0
searx/engines/seedpeer.py

@@ -0,0 +1,78 @@
+#  Seedpeer (Videos, Music, Files)
+#
+# @website     http://seedpeer.eu
+# @provide-api no (nothing found)
+#
+# @using-api   no
+# @results     HTML (using search portal)
+# @stable      yes (HTML can change)
+# @parse       url, title, content, seed, leech, magnetlink
+
+from urlparse import urljoin
+from cgi import escape
+from urllib import quote
+from lxml import html
+from operator import itemgetter
+from searx.engines.xpath import extract_text
+
+
+url = 'http://www.seedpeer.eu/'
+search_url = url + 'search/{search_term}/7/{page_no}.html'
+# specific xpath variables
+torrent_xpath = '//*[@id="body"]/center/center/table[2]/tr/td/a'
+alternative_torrent_xpath = '//*[@id="body"]/center/center/table[1]/tr/td/a'
+title_xpath = '//*[@id="body"]/center/center/table[2]/tr/td/a/text()'
+alternative_title_xpath = '//*[@id="body"]/center/center/table/tr/td/a'
+seeds_xpath = '//*[@id="body"]/center/center/table[2]/tr/td[4]/font/text()'
+alternative_seeds_xpath = '//*[@id="body"]/center/center/table/tr/td[4]/font/text()'
+peers_xpath = '//*[@id="body"]/center/center/table[2]/tr/td[5]/font/text()'
+alternative_peers_xpath = '//*[@id="body"]/center/center/table/tr/td[5]/font/text()'
+age_xpath = '//*[@id="body"]/center/center/table[2]/tr/td[2]/text()'
+alternative_age_xpath = '//*[@id="body"]/center/center/table/tr/td[2]/text()'
+size_xpath = '//*[@id="body"]/center/center/table[2]/tr/td[3]/text()'
+alternative_size_xpath = '//*[@id="body"]/center/center/table/tr/td[3]/text()'
+
+
+# do search-request
+def request(query, params):
+    params['url'] = search_url.format(search_term=quote(query),
+                                      page_no=params['pageno'] - 1)
+    return params
+
+
+# get response from search-request
+def response(resp):
+    results = []
+    dom = html.fromstring(resp.text)
+    torrent_links = dom.xpath(torrent_xpath)
+    if len(torrent_links) > 0:
+        seeds = dom.xpath(seeds_xpath)
+        peers = dom.xpath(peers_xpath)
+        titles = dom.xpath(title_xpath)
+        sizes = dom.xpath(size_xpath)
+        ages = dom.xpath(age_xpath)
+    else:  # under ~5 results uses a different xpath
+        torrent_links = dom.xpath(alternative_torrent_xpath)
+        seeds = dom.xpath(alternative_seeds_xpath)
+        peers = dom.xpath(alternative_peers_xpath)
+        titles = dom.xpath(alternative_title_xpath)
+        sizes = dom.xpath(alternative_size_xpath)
+        ages = dom.xpath(alternative_age_xpath)
+    # return empty array if nothing is found
+    if not torrent_links:
+        return []
+
+    # parse results
+    for index, result in enumerate(torrent_links):
+        link = result.attrib.get('href')
+        href = urljoin(url, link)
+        results.append({'url': href,
+                        'title': titles[index].text_content(),
+                        'content': '{}, {}'.format(sizes[index], ages[index]),
+                        'seed': seeds[index],
+                        'leech': peers[index],
+
+                        'template': 'torrent.html'})
+
+    # return results sorted by seeder
+    return sorted(results, key=itemgetter('seed'), reverse=True)

+ 26 - 1
searx/settings.yml

@@ -18,6 +18,12 @@ ui:
     default_theme : oscar # ui theme
     default_theme : oscar # ui theme
     default_locale : "" # Default interface locale - leave blank to detect from browser information or use codes from the 'locales' config section
     default_locale : "" # Default interface locale - leave blank to detect from browser information or use codes from the 'locales' config section
 
 
+# searx supports result proxification using an external service: https://github.com/asciimoo/morty
+# uncomment below section if you have running morty proxy
+#result_proxy:
+#    url : http://127.0.0.1:3000/
+#    key : your_morty_proxy_key
+
 outgoing: # communication with search engines
 outgoing: # communication with search engines
     request_timeout : 2.0 # seconds
     request_timeout : 2.0 # seconds
     useragent_suffix : "" # suffix of searx_useragent, could contain informations like an email address to the administrator
     useragent_suffix : "" # suffix of searx_useragent, could contain informations like an email address to the administrator
@@ -301,6 +307,12 @@ engines:
     timeout : 6.0
     timeout : 6.0
     disabled : True
     disabled : True
 
 
+  - name: kickass
+    engine : kickass
+    shortcut : kc
+    timeout : 4.0
+    disabled : True
+
   - name : microsoft academic
   - name : microsoft academic
     engine : json_engine
     engine : json_engine
     paging : True
     paging : True
@@ -339,6 +351,13 @@ engines:
     disabled : True
     disabled : True
     shortcut : or
     shortcut : or
 
 
+  - name : pdbe
+    engine : pdbe
+    shortcut : pdb
+# Hide obsolete PDB entries.
+# Default is not to hide obsolete structures
+#    hide_obsolete : False
+
   - name : photon
   - name : photon
     engine : photon
     engine : photon
     shortcut : ph
     shortcut : ph
@@ -377,7 +396,7 @@ engines:
     timeout : 10.0
     timeout : 10.0
     disabled : True
     disabled : True
 
 
-  - name : scanr_structures
+  - name : scanr structures
     shortcut: scs
     shortcut: scs
     engine : scanr_structures
     engine : scanr_structures
     disabled : True
     disabled : True
@@ -495,6 +514,12 @@ engines:
     timeout: 6.0
     timeout: 6.0
     categories : science
     categories : science
 
 
+  - name : seedpeer
+    engine : seedpeer
+    shortcut: speu
+    categories: files, music, videos
+    disabled: True
+
   - name : dictzone
   - name : dictzone
     engine : dictzone
     engine : dictzone
     shortcut : dc
     shortcut : dc

+ 3 - 3
searx/settings_robot.yml

@@ -15,7 +15,7 @@ server:
 
 
 ui:
 ui:
     themes_path : ""
     themes_path : ""
-    default_theme : default
+    default_theme : legacy
     default_locale : ""
     default_locale : ""
 
 
 outgoing:
 outgoing:
@@ -23,12 +23,12 @@ outgoing:
     useragent_suffix : ""
     useragent_suffix : ""
 
 
 engines:
 engines:
-  - name : general_dummy
+  - name : general dummy
     engine : dummy
     engine : dummy
     categories : general
     categories : general
     shortcut : gd
     shortcut : gd
 
 
-  - name : dummy_dummy
+  - name : dummy dummy
     engine : dummy
     engine : dummy
     categories : dummy
     categories : dummy
     shortcut : dd
     shortcut : dd

+ 0 - 0
searx/static/themes/default/css/style-rtl.css → searx/static/themes/legacy/css/style-rtl.css


+ 0 - 0
searx/static/themes/default/css/style.css → searx/static/themes/legacy/css/style.css


+ 0 - 0
searx/static/themes/default/img/favicon.png → searx/static/themes/legacy/img/favicon.png


+ 0 - 0
searx/static/themes/default/img/github_ribbon.png → searx/static/themes/legacy/img/github_ribbon.png


+ 0 - 0
searx/static/themes/default/img/icons/icon_500px.ico → searx/static/themes/legacy/img/icons/icon_500px.ico


+ 0 - 0
searx/static/themes/default/img/icons/icon_bing.ico → searx/static/themes/legacy/img/icons/icon_bing.ico


+ 0 - 0
searx/static/themes/default/img/icons/icon_dailymotion.ico → searx/static/themes/legacy/img/icons/icon_dailymotion.ico


+ 0 - 0
searx/static/themes/default/img/icons/icon_deezer.ico → searx/static/themes/legacy/img/icons/icon_deezer.ico


+ 0 - 0
searx/static/themes/default/img/icons/icon_deviantart.ico → searx/static/themes/legacy/img/icons/icon_deviantart.ico


+ 0 - 0
searx/static/themes/default/img/icons/icon_digg.ico → searx/static/themes/legacy/img/icons/icon_digg.ico


+ 0 - 0
searx/static/themes/default/img/icons/icon_duckduckgo.ico → searx/static/themes/legacy/img/icons/icon_duckduckgo.ico


+ 0 - 0
searx/static/themes/default/img/icons/icon_flickr.ico → searx/static/themes/legacy/img/icons/icon_flickr.ico


+ 0 - 0
searx/static/themes/default/img/icons/icon_github.ico → searx/static/themes/legacy/img/icons/icon_github.ico


+ 0 - 0
searx/static/themes/default/img/icons/icon_google play apps.ico → searx/static/themes/legacy/img/icons/icon_google play apps.ico


+ 0 - 0
searx/static/themes/default/img/icons/icon_google play movies.ico → searx/static/themes/legacy/img/icons/icon_google play movies.ico


+ 0 - 0
searx/static/themes/default/img/icons/icon_google play music.ico → searx/static/themes/legacy/img/icons/icon_google play music.ico


+ 0 - 0
searx/static/themes/default/img/icons/icon_google.ico → searx/static/themes/legacy/img/icons/icon_google.ico


+ 0 - 0
searx/static/themes/default/img/icons/icon_kickass.ico → searx/static/themes/legacy/img/icons/icon_kickass.ico


+ 0 - 0
searx/static/themes/default/img/icons/icon_openstreetmap.ico → searx/static/themes/legacy/img/icons/icon_openstreetmap.ico


+ 0 - 0
searx/static/themes/default/img/icons/icon_searchcode code.ico → searx/static/themes/legacy/img/icons/icon_searchcode code.ico


+ 0 - 0
searx/static/themes/default/img/icons/icon_searchcode doc.ico → searx/static/themes/legacy/img/icons/icon_searchcode doc.ico


+ 0 - 0
searx/static/themes/default/img/icons/icon_searchcode.ico → searx/static/themes/legacy/img/icons/icon_searchcode.ico


+ 0 - 0
searx/static/themes/default/img/icons/icon_soundcloud.ico → searx/static/themes/legacy/img/icons/icon_soundcloud.ico


+ 0 - 0
searx/static/themes/default/img/icons/icon_stackoverflow.ico → searx/static/themes/legacy/img/icons/icon_stackoverflow.ico


+ 0 - 0
searx/static/themes/default/img/icons/icon_startpage.ico → searx/static/themes/legacy/img/icons/icon_startpage.ico


+ 0 - 0
searx/static/themes/default/img/icons/icon_subtitleseeker.ico → searx/static/themes/legacy/img/icons/icon_subtitleseeker.ico


+ 0 - 0
searx/static/themes/default/img/icons/icon_twitter.ico → searx/static/themes/legacy/img/icons/icon_twitter.ico


+ 0 - 0
searx/static/themes/default/img/icons/icon_vimeo.ico → searx/static/themes/legacy/img/icons/icon_vimeo.ico


+ 0 - 0
searx/static/themes/default/img/icons/icon_wikipedia.ico → searx/static/themes/legacy/img/icons/icon_wikipedia.ico


+ 0 - 0
searx/static/themes/default/img/icons/icon_yahoo.ico → searx/static/themes/legacy/img/icons/icon_yahoo.ico


+ 0 - 0
searx/static/themes/default/img/icons/icon_youtube.ico → searx/static/themes/legacy/img/icons/icon_youtube.ico


+ 0 - 0
searx/static/themes/default/img/preference-icon.png → searx/static/themes/legacy/img/preference-icon.png


+ 0 - 0
searx/static/themes/default/img/search-icon.png → searx/static/themes/legacy/img/search-icon.png


+ 0 - 0
searx/static/themes/default/img/searx.png → searx/static/themes/legacy/img/searx.png


+ 0 - 0
searx/static/themes/default/img/searx_logo.svg → searx/static/themes/legacy/img/searx_logo.svg


+ 0 - 0
searx/static/themes/default/js/searx.js → searx/static/themes/legacy/js/searx.js


+ 0 - 0
searx/static/themes/default/less/autocompleter.less → searx/static/themes/legacy/less/autocompleter.less


+ 0 - 0
searx/static/themes/default/less/code.less → searx/static/themes/legacy/less/code.less


+ 0 - 0
searx/static/themes/default/less/definitions.less → searx/static/themes/legacy/less/definitions.less


+ 0 - 0
searx/static/themes/default/less/mixins.less → searx/static/themes/legacy/less/mixins.less


+ 0 - 0
searx/static/themes/default/less/search.less → searx/static/themes/legacy/less/search.less


+ 0 - 0
searx/static/themes/default/less/style-rtl.less → searx/static/themes/legacy/less/style-rtl.less


+ 0 - 0
searx/static/themes/default/less/style.less → searx/static/themes/legacy/less/style.less


+ 1 - 1
searx/templates/courgette/base.html

@@ -22,7 +22,7 @@
         {% endblock %}
         {% endblock %}
         {% block meta %}{% endblock %}
         {% block meta %}{% endblock %}
         {% block head %}
         {% block head %}
-        <link title="searx" type="application/opensearchdescription+xml" rel="search" href="{{ url_for('opensearch') }}"/>
+        <link title="{{ instance_name }}" type="application/opensearchdescription+xml" rel="search" href="{{ url_for('opensearch') }}"/>
         {% endblock %}
         {% endblock %}
         <script type="text/javascript">
         <script type="text/javascript">
             searx = {};
             searx = {};

+ 1 - 1
searx/templates/default/404.html → searx/templates/legacy/404.html

@@ -1,4 +1,4 @@
-{% extends "default/base.html" %}
+{% extends "legacy/base.html" %}
 {% block content %}
 {% block content %}
 <div class="center">
 <div class="center">
     <h1>{{ _('Page not found') }}</h1>
     <h1>{{ _('Page not found') }}</h1>

+ 2 - 2
searx/templates/default/about.html → searx/templates/legacy/about.html

@@ -1,6 +1,6 @@
-{% extends 'default/base.html' %}
+{% extends 'legacy/base.html' %}
 {% block content %}
 {% block content %}
-{% include 'default/github_ribbon.html' %}
+{% include 'legacy/github_ribbon.html' %}
 <div class="row"{% if rtl %} dir="ltr"{% endif %}>
 <div class="row"{% if rtl %} dir="ltr"{% endif %}>
     <h1>About <a href="{{ url_for('index') }}">searx</a></h1>
     <h1>About <a href="{{ url_for('index') }}">searx</a></h1>
 
 

+ 1 - 1
searx/templates/default/base.html → searx/templates/legacy/base.html

@@ -17,7 +17,7 @@
         {% endblock %}
         {% endblock %}
         {% block meta %}{% endblock %}
         {% block meta %}{% endblock %}
         {% block head %}
         {% block head %}
-        <link title="searx" type="application/opensearchdescription+xml" rel="search" href="{{ url_for('opensearch') }}"/>
+        <link title="{{ instance_name }}" type="application/opensearchdescription+xml" rel="search" href="{{ url_for('opensearch') }}"/>
         {% endblock %}
         {% endblock %}
     </head>
     </head>
     <body>
     <body>

+ 0 - 0
searx/templates/default/categories.html → searx/templates/legacy/categories.html


+ 0 - 0
searx/templates/default/github_ribbon.html → searx/templates/legacy/github_ribbon.html


+ 3 - 3
searx/templates/default/index.html → searx/templates/legacy/index.html

@@ -1,8 +1,8 @@
-{% extends "default/base.html" %}
+{% extends "legacy/base.html" %}
 {% block content %}
 {% block content %}
 <div class="center">
 <div class="center">
     <div class="title"><h1>searx</h1></div>
     <div class="title"><h1>searx</h1></div>
-    {% include 'default/search.html' %}
+    {% include 'legacy/search.html' %}
     <p class="top_margin">
     <p class="top_margin">
     	{% if rtl %}
     	{% if rtl %}
     	<a href="{{ url_for('preferences') }}" class="hmarg">{{ _('preferences') }}</a>
     	<a href="{{ url_for('preferences') }}" class="hmarg">{{ _('preferences') }}</a>
@@ -13,6 +13,6 @@
         {% endif %}
         {% endif %}
     </p>
     </p>
 </div>
 </div>
-{% include 'default/github_ribbon.html' %}
+{% include 'legacy/github_ribbon.html' %}
 {% endblock %}
 {% endblock %}
 
 

+ 0 - 0
searx/templates/default/infobox.html → searx/templates/legacy/infobox.html


+ 0 - 0
searx/templates/default/opensearch.xml → searx/templates/legacy/opensearch.xml


+ 0 - 0
searx/templates/default/opensearch_response_rss.xml → searx/templates/legacy/opensearch_response_rss.xml


+ 2 - 2
searx/templates/default/preferences.html → searx/templates/legacy/preferences.html

@@ -1,4 +1,4 @@
-{% extends "default/base.html" %}
+{% extends "legacy/base.html" %}
 {% block head %} {% endblock %}
 {% block head %} {% endblock %}
 {% block content %}
 {% block content %}
 <div class="row">
 <div class="row">
@@ -8,7 +8,7 @@
     <fieldset>
     <fieldset>
         <legend>{{ _('Default categories') }}</legend>
         <legend>{{ _('Default categories') }}</legend>
         {% set display_tooltip = false %}
         {% set display_tooltip = false %}
-        {% include 'default/categories.html' %}
+        {% include 'legacy/categories.html' %}
     </fieldset>
     </fieldset>
     <fieldset>
     <fieldset>
         <legend>{{ _('Search language') }}</legend>
         <legend>{{ _('Search language') }}</legend>

+ 0 - 0
searx/templates/default/result_templates/code.html → searx/templates/legacy/result_templates/code.html


+ 0 - 0
searx/templates/default/result_templates/default.html → searx/templates/legacy/result_templates/default.html


+ 0 - 0
searx/templates/default/result_templates/images.html → searx/templates/legacy/result_templates/images.html


+ 0 - 0
searx/templates/default/result_templates/map.html → searx/templates/legacy/result_templates/map.html


+ 0 - 0
searx/templates/default/result_templates/torrent.html → searx/templates/legacy/result_templates/torrent.html


+ 0 - 0
searx/templates/default/result_templates/videos.html → searx/templates/legacy/result_templates/videos.html


+ 5 - 5
searx/templates/default/results.html → searx/templates/legacy/results.html

@@ -1,10 +1,10 @@
-{% extends "default/base.html" %}
+{% extends "legacy/base.html" %}
 {% block title %}{{ q }} - {% endblock %}
 {% block title %}{{ q }} - {% endblock %}
 {% block meta %}<link rel="alternate" type="application/rss+xml" title="Searx search: {{ q }}" href="{{ url_for('index') }}?q={{ q|urlencode }}&amp;format=rss&amp;{% for category in selected_categories %}category_{{ category }}=1&amp;{% endfor %}pageno={{ pageno }}">{% endblock %}
 {% block meta %}<link rel="alternate" type="application/rss+xml" title="Searx search: {{ q }}" href="{{ url_for('index') }}?q={{ q|urlencode }}&amp;format=rss&amp;{% for category in selected_categories %}category_{{ category }}=1&amp;{% endfor %}pageno={{ pageno }}">{% endblock %}
 {% block content %}
 {% block content %}
 <div class="preferences_container right"><a href="{{ url_for('preferences') }}" id="preferences"><span>preferences</span></a></div>
 <div class="preferences_container right"><a href="{{ url_for('preferences') }}" id="preferences"><span>preferences</span></a></div>
 <div class="small search center">
 <div class="small search center">
-    {% include 'default/search.html' %}
+    {% include 'legacy/search.html' %}
 </div>
 </div>
 <div id="results">
 <div id="results">
     <div id="sidebar">
     <div id="sidebar">
@@ -55,16 +55,16 @@
     {% if infoboxes %}
     {% if infoboxes %}
     <div id="infoboxes">
     <div id="infoboxes">
       {% for infobox in infoboxes %}
       {% for infobox in infoboxes %}
-         {% include 'default/infobox.html' %}
+         {% include 'legacy/infobox.html' %}
       {% endfor %}
       {% endfor %}
     </div>
     </div>
     {% endif %}
     {% endif %}
 
 
     {% for result in results %}
     {% for result in results %}
         {% if result['template'] %}
         {% if result['template'] %}
-            {% include get_result_template('default', result['template']) %}
+            {% include get_result_template('legacy', result['template']) %}
         {% else %}
         {% else %}
-            {% include 'default/result_templates/default.html' %}
+            {% include 'legacy/result_templates/default.html' %}
         {% endif %}
         {% endif %}
     {% endfor %}
     {% endfor %}
 
 

+ 1 - 1
searx/templates/default/search.html → searx/templates/legacy/search.html

@@ -4,5 +4,5 @@
         <input type="submit" value="search" id="search_submit" />
         <input type="submit" value="search" id="search_submit" />
     </div>
     </div>
     {% set display_tooltip = true %}
     {% set display_tooltip = true %}
-    {% include 'default/categories.html' %}
+    {% include 'legacy/categories.html' %}
 </form>
 </form>

+ 1 - 1
searx/templates/default/stats.html → searx/templates/legacy/stats.html

@@ -1,4 +1,4 @@
-{% extends "default/base.html" %}
+{% extends "legacy/base.html" %}
 {% block head %} {% endblock %}
 {% block head %} {% endblock %}
 {% block content %}
 {% block content %}
 <h2>{{ _('Engine stats') }}</h2>
 <h2>{{ _('Engine stats') }}</h2>

+ 6 - 0
searx/templates/oscar/macros.html

@@ -33,6 +33,9 @@
         <span class="label label-default">{{ engine }}</span>
         <span class="label label-default">{{ engine }}</span>
     {% endfor %}
     {% endfor %}
     <small>{{ result_link("https://web.archive.org/web/" + result.url, icon('link') + _('cached'), "text-info") }}</small>
     <small>{{ result_link("https://web.archive.org/web/" + result.url, icon('link') + _('cached'), "text-info") }}</small>
+    {% if proxify %}
+    <small>{{ result_link(proxify(result.url), icon('sort') + _('proxied'), "text-info") }}</small>
+    {% endif %}
 </div>
 </div>
     <div class="text-muted"><small>{{ result.pretty_url }}</small></div>
     <div class="text-muted"><small>{{ result.pretty_url }}</small></div>
 {%- endmacro %}
 {%- endmacro %}
@@ -44,6 +47,9 @@
         <span class="label label-default">{{ engine }}</span>
         <span class="label label-default">{{ engine }}</span>
     {% endfor %}
     {% endfor %}
     <small>{{ result_link("https://web.archive.org/web/" + result.url, icon('link') + _('cached'), "text-info") }}</small>
     <small>{{ result_link("https://web.archive.org/web/" + result.url, icon('link') + _('cached'), "text-info") }}</small>
+    {% if proxify %}
+    <small>{{ result_link(proxify(result.url), icon('sort') + _('proxied'), "text-info") }}</small>
+    {% endif %}
     <div class="text-muted"><small>{{ result.pretty_url }}</small></div>
     <div class="text-muted"><small>{{ result.pretty_url }}</small></div>
 {%- endmacro %}
 {%- endmacro %}
 
 

+ 1 - 1
searx/templates/pix-art/preferences.html

@@ -1,4 +1,4 @@
-{% extends "default/base.html" %}
+{% extends "legacy/base.html" %}
 {% block head %} {% endblock %}
 {% block head %} {% endblock %}
 {% block content %}
 {% block content %}
 <div class="row">
 <div class="row">

+ 1 - 1
searx/templates/pix-art/stats.html

@@ -1,4 +1,4 @@
-{% extends "default/base.html" %}
+{% extends "legacy/base.html" %}
 {% block head %} {% endblock %}
 {% block head %} {% endblock %}
 {% block content %}
 {% block content %}
 <h2>{{ _('Engine stats') }}</h2>
 <h2>{{ _('Engine stats') }}</h2>

+ 15 - 0
searx/utils.py

@@ -252,12 +252,27 @@ def get_torrent_size(filesize, filesize_multiplier):
             filesize = int(filesize * 1024 * 1024)
             filesize = int(filesize * 1024 * 1024)
         elif filesize_multiplier == 'KB':
         elif filesize_multiplier == 'KB':
             filesize = int(filesize * 1024)
             filesize = int(filesize * 1024)
+        elif filesize_multiplier == 'TiB':
+            filesize = int(filesize * 1000 * 1000 * 1000 * 1000)
+        elif filesize_multiplier == 'GiB':
+            filesize = int(filesize * 1000 * 1000 * 1000)
+        elif filesize_multiplier == 'MiB':
+            filesize = int(filesize * 1000 * 1000)
+        elif filesize_multiplier == 'KiB':
+            filesize = int(filesize * 1000)
     except:
     except:
         filesize = None
         filesize = None
 
 
     return filesize
     return filesize
 
 
 
 
+def convert_str_to_int(number_str):
+    if number_str.isdigit():
+        return int(number_str)
+    else:
+        return 0
+
+
 def is_valid_lang(lang):
 def is_valid_lang(lang):
     is_abbr = (len(lang) == 2)
     is_abbr = (len(lang) == 2)
     if is_abbr:
     if is_abbr:

+ 22 - 5
searx/webapp.py

@@ -22,10 +22,11 @@ if __name__ == '__main__':
     from os.path import realpath, dirname
     from os.path import realpath, dirname
     path.append(realpath(dirname(realpath(__file__)) + '/../'))
     path.append(realpath(dirname(realpath(__file__)) + '/../'))
 
 
-import json
 import cStringIO
 import cStringIO
-import os
 import hashlib
 import hashlib
+import hmac
+import json
+import os
 import requests
 import requests
 
 
 from searx import logger
 from searx import logger
@@ -245,6 +246,20 @@ def url_for_theme(endpoint, override_theme=None, **values):
     return url_for(endpoint, **values)
     return url_for(endpoint, **values)
 
 
 
 
+def proxify(url):
+    if url.startswith('//'):
+        url = 'https:' + url
+
+    if not settings.get('result_proxy'):
+        return url
+
+    h = hmac.new(settings['result_proxy']['key'], url.encode('utf-8'), hashlib.sha256).hexdigest()
+
+    return '{0}?{1}'.format(settings['result_proxy']['url'],
+                            urlencode(dict(mortyurl=url.encode('utf-8'),
+                                           mortyhash=h)))
+
+
 def image_proxify(url):
 def image_proxify(url):
 
 
     if url.startswith('//'):
     if url.startswith('//'):
@@ -253,8 +268,7 @@ def image_proxify(url):
     if not request.preferences.get_value('image_proxy'):
     if not request.preferences.get_value('image_proxy'):
         return url
         return url
 
 
-    hash_string = url + settings['server']['secret_key']
-    h = hashlib.sha256(hash_string.encode('utf-8')).hexdigest()
+    h = hmac.new(settings['server']['secret_key'], url.encode('utf-8'), hashlib.sha256).hexdigest()
 
 
     return '{0}?{1}'.format(url_for('image_proxy'),
     return '{0}?{1}'.format(url_for('image_proxy'),
                             urlencode(dict(url=url.encode('utf-8'), h=h)))
                             urlencode(dict(url=url.encode('utf-8'), h=h)))
@@ -313,6 +327,8 @@ def render(template_name, override_theme=None, **kwargs):
 
 
     kwargs['image_proxify'] = image_proxify
     kwargs['image_proxify'] = image_proxify
 
 
+    kwargs['proxify'] = proxify if settings.get('result_proxy') else None
+
     kwargs['get_result_template'] = get_result_template
     kwargs['get_result_template'] = get_result_template
 
 
     kwargs['theme'] = get_current_theme_name(override=override_theme)
     kwargs['theme'] = get_current_theme_name(override=override_theme)
@@ -602,7 +618,7 @@ def image_proxy():
     if not url:
     if not url:
         return '', 400
         return '', 400
 
 
-    h = hashlib.sha256(url + settings['server']['secret_key'].encode('utf-8')).hexdigest()
+    h = hmac.new(settings['server']['secret_key'], url, hashlib.sha256).hexdigest()
 
 
     if h != request.args.get('h'):
     if h != request.args.get('h'):
         return '', 400
         return '', 400
@@ -660,6 +676,7 @@ Allow: /
 Allow: /about
 Allow: /about
 Disallow: /stats
 Disallow: /stats
 Disallow: /preferences
 Disallow: /preferences
+Disallow: /*?*q=*
 """, mimetype='text/plain')
 """, mimetype='text/plain')
 
 
 
 

+ 24 - 28
tests/robot/test_basic.robot

@@ -4,6 +4,14 @@ Test Setup      Open Browser  http://localhost:11111/
 Test Teardown   Close All Browsers
 Test Teardown   Close All Browsers
 
 
 
 
+*** Keywords ***
+Submit Preferences
+    Set Selenium Speed  2 seconds
+    Submit Form  id=search_form
+    Location Should Be  http://localhost:11111/
+    Set Selenium Speed  0 seconds
+
+
 *** Test Cases ***
 *** Test Cases ***
 Front page
 Front page
     Page Should Contain  about
     Page Should Contain  about
@@ -24,8 +32,8 @@ Preferences page
     Page Should Contain  Preferences
     Page Should Contain  Preferences
     Page Should Contain  Default categories
     Page Should Contain  Default categories
     Page Should Contain  Currently used search engines
     Page Should Contain  Currently used search engines
-    Page Should Contain  dummy_dummy
-    Page Should Contain  general_dummy
+    Page Should Contain  dummy dummy
+    Page Should Contain  general dummy
 
 
 Switch category
 Switch category
     Go To  http://localhost:11111/preferences
     Go To  http://localhost:11111/preferences
@@ -33,8 +41,7 @@ Switch category
     Page Should Contain Checkbox  category_dummy
     Page Should Contain Checkbox  category_dummy
     Click Element  xpath=//*[.="general"]
     Click Element  xpath=//*[.="general"]
     Click Element  xpath=//*[.="dummy"]
     Click Element  xpath=//*[.="dummy"]
-    Submit Form  id=search_form
-    Location Should Be  http://localhost:11111/
+    Submit Preferences
     Checkbox Should Not Be Selected  category_general
     Checkbox Should Not Be Selected  category_general
     Checkbox Should Be Selected  category_dummy
     Checkbox Should Be Selected  category_dummy
 
 
@@ -43,8 +50,7 @@ Change language
     Page Should Contain  preferences
     Page Should Contain  preferences
     Go To  http://localhost:11111/preferences
     Go To  http://localhost:11111/preferences
     Select From List  locale  hu
     Select From List  locale  hu
-    Submit Form  id=search_form
-    Location Should Be  http://localhost:11111/
+    Submit Preferences
     Page Should Contain  rólunk
     Page Should Contain  rólunk
     Page Should Contain  beállítások
     Page Should Contain  beállítások
 
 
@@ -53,13 +59,11 @@ Change method
     Page Should Contain  preferences
     Page Should Contain  preferences
     Go To  http://localhost:11111/preferences
     Go To  http://localhost:11111/preferences
     Select From List  method  GET
     Select From List  method  GET
-    Submit Form  id=search_form
-    Location Should Be  http://localhost:11111/
+    Submit Preferences
     Go To  http://localhost:11111/preferences
     Go To  http://localhost:11111/preferences
     List Selection Should Be  method  GET
     List Selection Should Be  method  GET
     Select From List  method  POST
     Select From List  method  POST
-    Submit Form  id=search_form
-    Location Should Be  http://localhost:11111/
+    Submit Preferences
     Go To  http://localhost:11111/preferences
     Go To  http://localhost:11111/preferences
     List Selection Should Be  method  POST
     List Selection Should Be  method  POST
 
 
@@ -67,10 +71,9 @@ Change theme
     Page Should Contain  about
     Page Should Contain  about
     Page Should Contain  preferences
     Page Should Contain  preferences
     Go To  http://localhost:11111/preferences
     Go To  http://localhost:11111/preferences
-    List Selection Should Be  theme  default
+    List Selection Should Be  theme  legacy
     Select From List  theme  oscar
     Select From List  theme  oscar
-    Submit Form  id=search_form
-    Location Should Be  http://localhost:11111/
+    Submit Preferences
     Go To  http://localhost:11111/preferences
     Go To  http://localhost:11111/preferences
     List Selection Should Be  theme  oscar
     List Selection Should Be  theme  oscar
 
 
@@ -80,8 +83,7 @@ Change safesearch
     Go To  http://localhost:11111/preferences
     Go To  http://localhost:11111/preferences
     List Selection Should Be  safesearch  None
     List Selection Should Be  safesearch  None
     Select From List  safesearch  Strict
     Select From List  safesearch  Strict
-    Submit Form  id=search_form
-    Location Should Be  http://localhost:11111/
+    Submit Preferences
     Go To  http://localhost:11111/preferences
     Go To  http://localhost:11111/preferences
     List Selection Should Be  safesearch  Strict
     List Selection Should Be  safesearch  Strict
 
 
@@ -91,8 +93,7 @@ Change image proxy
     Go To  http://localhost:11111/preferences
     Go To  http://localhost:11111/preferences
     List Selection Should Be  image_proxy  Disabled
     List Selection Should Be  image_proxy  Disabled
     Select From List  image_proxy  Enabled
     Select From List  image_proxy  Enabled
-    Submit Form  id=search_form
-    Location Should Be  http://localhost:11111/
+    Submit Preferences
     Go To  http://localhost:11111/preferences
     Go To  http://localhost:11111/preferences
     List Selection Should Be  image_proxy  Enabled
     List Selection Should Be  image_proxy  Enabled
 
 
@@ -102,8 +103,7 @@ Change search language
     Go To  http://localhost:11111/preferences
     Go To  http://localhost:11111/preferences
     List Selection Should Be  language  Automatic
     List Selection Should Be  language  Automatic
     Select From List  language  Turkish (Turkey) - tr_TR
     Select From List  language  Turkish (Turkey) - tr_TR
-    Submit Form  id=search_form
-    Location Should Be  http://localhost:11111/
+    Submit Preferences
     Go To  http://localhost:11111/preferences
     Go To  http://localhost:11111/preferences
     List Selection Should Be  language  Turkish (Turkey) - tr_TR
     List Selection Should Be  language  Turkish (Turkey) - tr_TR
 
 
@@ -113,8 +113,7 @@ Change autocomplete
     Go To  http://localhost:11111/preferences
     Go To  http://localhost:11111/preferences
     List Selection Should Be  autocomplete  -
     List Selection Should Be  autocomplete  -
     Select From List  autocomplete  google
     Select From List  autocomplete  google
-    Submit Form  id=search_form
-    Location Should Be  http://localhost:11111/
+    Submit Preferences
     Go To  http://localhost:11111/preferences
     Go To  http://localhost:11111/preferences
     List Selection Should Be  autocomplete  google
     List Selection Should Be  autocomplete  google
 
 
@@ -126,8 +125,7 @@ Change allowed/disabled engines
     Element Should Contain  xpath=//label[@class="deny"][@for='engine_dummy_dummy_dummy']  Block
     Element Should Contain  xpath=//label[@class="deny"][@for='engine_dummy_dummy_dummy']  Block
     Element Should Contain  xpath=//label[@class="deny"][@for='engine_general_general_dummy']  Block
     Element Should Contain  xpath=//label[@class="deny"][@for='engine_general_general_dummy']  Block
     Click Element  xpath=//label[@class="deny"][@for='engine_general_general_dummy']
     Click Element  xpath=//label[@class="deny"][@for='engine_general_general_dummy']
-    Submit Form  id=search_form
-    Location Should Be  http://localhost:11111/
+    Submit Preferences
     Page Should Contain  about
     Page Should Contain  about
     Page Should Contain  preferences
     Page Should Contain  preferences
     Go To  http://localhost:11111/preferences
     Go To  http://localhost:11111/preferences
@@ -139,18 +137,16 @@ Block a plugin
     Page Should Contain  about
     Page Should Contain  about
     Page Should Contain  preferences
     Page Should Contain  preferences
     Go To  http://localhost:11111/preferences
     Go To  http://localhost:11111/preferences
-    List Selection Should Be  theme  default
+    List Selection Should Be  theme  legacy
     Select From List  theme  oscar
     Select From List  theme  oscar
-    Submit Form  id=search_form
-    Location Should Be  http://localhost:11111/
+    Submit Preferences
     Go To  http://localhost:11111/preferences
     Go To  http://localhost:11111/preferences
     List Selection Should Be  theme  oscar
     List Selection Should Be  theme  oscar
     Page Should Contain  Plugins
     Page Should Contain  Plugins
     Click Link  Plugins
     Click Link  Plugins
     Checkbox Should Not Be Selected  id=plugin_HTTPS_rewrite
     Checkbox Should Not Be Selected  id=plugin_HTTPS_rewrite
     Click Element  xpath=//label[@for='plugin_HTTPS_rewrite']
     Click Element  xpath=//label[@for='plugin_HTTPS_rewrite']
-    Submit Form  id=search_form
-    Location Should Be  http://localhost:11111/
+    Submit Preferences
     Go To  http://localhost:11111/preferences
     Go To  http://localhost:11111/preferences
     Page Should Contain  Plugins
     Page Should Contain  Plugins
     Click Link  Plugins
     Click Link  Plugins

File diff suppressed because it is too large
+ 64 - 0
tests/unit/engines/seedpeer_fixture.html


+ 3 - 1
tests/unit/engines/test_digbt.py

@@ -28,7 +28,9 @@ class TestDigBTEngine(SearxTestCase):
         <table class="table">
         <table class="table">
             <tr><td class="x-item">
             <tr><td class="x-item">
             <div>
             <div>
-                <a title="The Big Bang Theory" class="title" href="/The-Big-Bang-Theory-d2.html">The Big Bang Theory</a>
+                <a title="The Big Bang Theory" class="title" href="/The-Big-Bang-Theory-d2.html">
+                    The Big <span class="highlight">Bang</span> Theory
+                </a>
                 <span class="ctime"><span style="color:red;">4 hours ago</span></span>
                 <span class="ctime"><span style="color:red;">4 hours ago</span></span>
             </div>
             </div>
             <div class="files">
             <div class="files">

+ 13 - 13
tests/unit/engines/test_kickass.py

@@ -14,7 +14,7 @@ class TestKickassEngine(SearxTestCase):
         params = kickass.request(query, dicto)
         params = kickass.request(query, dicto)
         self.assertIn('url', params)
         self.assertIn('url', params)
         self.assertIn(query, params['url'])
         self.assertIn(query, params['url'])
-        self.assertIn('kickass.to', params['url'])
+        self.assertIn('kickass.cd', params['url'])
         self.assertFalse(params['verify'])
         self.assertFalse(params['verify'])
 
 
     def test_response(self):
     def test_response(self):
@@ -84,7 +84,7 @@ class TestKickassEngine(SearxTestCase):
                         </span>
                         </span>
                     </div>
                     </div>
                 </td>
                 </td>
-                <td class="nobr center">449 <span>bytes</span></td>
+                <td class="nobr center">449 bytes</td>
                 <td class="center">4</td>
                 <td class="center">4</td>
                 <td class="center">2&nbsp;years</td>
                 <td class="center">2&nbsp;years</td>
                 <td class="green center">10</td>
                 <td class="green center">10</td>
@@ -97,7 +97,7 @@ class TestKickassEngine(SearxTestCase):
         self.assertEqual(type(results), list)
         self.assertEqual(type(results), list)
         self.assertEqual(len(results), 1)
         self.assertEqual(len(results), 1)
         self.assertEqual(results[0]['title'], 'This should be the title')
         self.assertEqual(results[0]['title'], 'This should be the title')
-        self.assertEqual(results[0]['url'], 'https://kickass.to/url.html')
+        self.assertEqual(results[0]['url'], 'https://kickass.cd/url.html')
         self.assertEqual(results[0]['content'], 'Posted by riri in Other &gt; Unsorted')
         self.assertEqual(results[0]['content'], 'Posted by riri in Other &gt; Unsorted')
         self.assertEqual(results[0]['seed'], 10)
         self.assertEqual(results[0]['seed'], 10)
         self.assertEqual(results[0]['leech'], 1)
         self.assertEqual(results[0]['leech'], 1)
@@ -191,7 +191,7 @@ class TestKickassEngine(SearxTestCase):
                         </span>
                         </span>
                     </div>
                     </div>
                 </td>
                 </td>
-                <td class="nobr center">1 <span>KB</span></td>
+                <td class="nobr center">1 KiB</td>
                 <td class="center">4</td>
                 <td class="center">4</td>
                 <td class="center">2&nbsp;years</td>
                 <td class="center">2&nbsp;years</td>
                 <td class="green center">10</td>
                 <td class="green center">10</td>
@@ -235,7 +235,7 @@ class TestKickassEngine(SearxTestCase):
                         </span>
                         </span>
                     </div>
                     </div>
                 </td>
                 </td>
-                <td class="nobr center">1 <span>MB</span></td>
+                <td class="nobr center">1 MiB</td>
                 <td class="center">4</td>
                 <td class="center">4</td>
                 <td class="center">2&nbsp;years</td>
                 <td class="center">2&nbsp;years</td>
                 <td class="green center">9</td>
                 <td class="green center">9</td>
@@ -279,7 +279,7 @@ class TestKickassEngine(SearxTestCase):
                         </span>
                         </span>
                     </div>
                     </div>
                 </td>
                 </td>
-                <td class="nobr center">1 <span>GB</span></td>
+                <td class="nobr center">1 GiB</td>
                 <td class="center">4</td>
                 <td class="center">4</td>
                 <td class="center">2&nbsp;years</td>
                 <td class="center">2&nbsp;years</td>
                 <td class="green center">8</td>
                 <td class="green center">8</td>
@@ -323,7 +323,7 @@ class TestKickassEngine(SearxTestCase):
                         </span>
                         </span>
                     </div>
                     </div>
                 </td>
                 </td>
-                <td class="nobr center">1 <span>TB</span></td>
+                <td class="nobr center">1 TiB</td>
                 <td class="center">4</td>
                 <td class="center">4</td>
                 <td class="center">2&nbsp;years</td>
                 <td class="center">2&nbsp;years</td>
                 <td class="green center">7</td>
                 <td class="green center">7</td>
@@ -367,7 +367,7 @@ class TestKickassEngine(SearxTestCase):
                         </span>
                         </span>
                     </div>
                     </div>
                 </td>
                 </td>
-                <td class="nobr center">z <span>bytes</span></td>
+                <td class="nobr center">z bytes</td>
                 <td class="center">r</td>
                 <td class="center">r</td>
                 <td class="center">2&nbsp;years</td>
                 <td class="center">2&nbsp;years</td>
                 <td class="green center">a</td>
                 <td class="green center">a</td>
@@ -380,17 +380,17 @@ class TestKickassEngine(SearxTestCase):
         self.assertEqual(type(results), list)
         self.assertEqual(type(results), list)
         self.assertEqual(len(results), 5)
         self.assertEqual(len(results), 5)
         self.assertEqual(results[0]['title'], 'This should be the title')
         self.assertEqual(results[0]['title'], 'This should be the title')
-        self.assertEqual(results[0]['url'], 'https://kickass.to/url.html')
+        self.assertEqual(results[0]['url'], 'https://kickass.cd/url.html')
         self.assertEqual(results[0]['content'], 'Posted by riri in Other &gt; Unsorted')
         self.assertEqual(results[0]['content'], 'Posted by riri in Other &gt; Unsorted')
         self.assertEqual(results[0]['seed'], 10)
         self.assertEqual(results[0]['seed'], 10)
         self.assertEqual(results[0]['leech'], 1)
         self.assertEqual(results[0]['leech'], 1)
         self.assertEqual(results[0]['files'], 4)
         self.assertEqual(results[0]['files'], 4)
         self.assertEqual(results[0]['magnetlink'], 'magnet:?xt=urn:btih:MAGNETURL&dn=test')
         self.assertEqual(results[0]['magnetlink'], 'magnet:?xt=urn:btih:MAGNETURL&dn=test')
         self.assertEqual(results[0]['torrentfile'], 'http://torcache.net/torrent/53917.torrent?title=test')
         self.assertEqual(results[0]['torrentfile'], 'http://torcache.net/torrent/53917.torrent?title=test')
-        self.assertEqual(results[0]['filesize'], 1024)
-        self.assertEqual(results[1]['filesize'], 1048576)
-        self.assertEqual(results[2]['filesize'], 1073741824)
-        self.assertEqual(results[3]['filesize'], 1099511627776)
+        self.assertEqual(results[0]['filesize'], 1000)
+        self.assertEqual(results[1]['filesize'], 1000000)
+        self.assertEqual(results[2]['filesize'], 1000000000)
+        self.assertEqual(results[3]['filesize'], 1000000000000)
         self.assertEqual(results[4]['seed'], 0)
         self.assertEqual(results[4]['seed'], 0)
         self.assertEqual(results[4]['leech'], 0)
         self.assertEqual(results[4]['leech'], 0)
         self.assertEqual(results[4]['files'], None)
         self.assertEqual(results[4]['files'], None)

+ 109 - 0
tests/unit/engines/test_pdbe.py

@@ -0,0 +1,109 @@
+import mock
+from collections import defaultdict
+from searx.engines import pdbe
+from searx.testing import SearxTestCase
+
+
+class TestPdbeEngine(SearxTestCase):
+    def test_request(self):
+        query = 'test_query'
+        dicto = defaultdict(dict)
+        params = pdbe.request(query, dicto)
+        self.assertTrue('url' in params)
+        self.assertTrue('ebi.ac.uk' in params['url'])
+        self.assertTrue('data' in params)
+        self.assertTrue('q' in params['data'])
+        self.assertTrue(query in params['data']['q'])
+        self.assertTrue('wt' in params['data'])
+        self.assertTrue('json' in params['data']['wt'])
+        self.assertTrue('method' in params)
+        self.assertTrue(params['method'] == 'POST')
+
+    def test_response(self):
+        self.assertRaises(AttributeError, pdbe.response, None)
+        self.assertRaises(AttributeError, pdbe.response, [])
+        self.assertRaises(AttributeError, pdbe.response, '')
+        self.assertRaises(AttributeError, pdbe.response, '[]')
+
+        json = """
+{
+  "response": {
+    "docs": [
+      {
+        "citation_title": "X-ray crystal structure of ferric Aplysia limacina myoglobin in different liganded states.",
+        "citation_year": 1993,
+        "entry_author_list": [
+          "Conti E, Moser C, Rizzi M, Mattevi A, Lionetti C, Coda A, Ascenzi P, Brunori M, Bolognesi M"
+        ],
+        "journal": "J. Mol. Biol.",
+        "journal_page": "498-508",
+        "journal_volume": "233",
+        "pdb_id": "2fal",
+        "status": "REL",
+        "title": "X-RAY CRYSTAL STRUCTURE OF FERRIC APLYSIA LIMACINA MYOGLOBIN IN DIFFERENT LIGANDED STATES"
+      }
+    ],
+    "numFound": 1,
+    "start": 0
+  },
+  "responseHeader": {
+    "QTime": 0,
+    "params": {
+      "q": "2fal",
+      "wt": "json"
+    },
+    "status": 0
+  }
+}
+"""
+
+        response = mock.Mock(text=json)
+        results = pdbe.response(response)
+        self.assertEqual(type(results), list)
+        self.assertEqual(len(results), 1)
+        self.assertEqual(results[0]['title'],
+                         'X-RAY CRYSTAL STRUCTURE OF FERRIC APLYSIA LIMACINA MYOGLOBIN IN DIFFERENT LIGANDED STATES')
+        self.assertEqual(results[0]['url'], pdbe.pdbe_entry_url.format(pdb_id='2fal'))
+        self.assertEqual(results[0]['img_src'], pdbe.pdbe_preview_url.format(pdb_id='2fal'))
+        self.assertTrue('Conti E' in results[0]['content'])
+        self.assertTrue('X-ray crystal structure of ferric Aplysia limacina myoglobin in different liganded states.' in
+                        results[0]['content'])
+        self.assertTrue('1993' in results[0]['content'])
+
+        # Testing proper handling of PDB entries marked as obsolete
+        json = """
+{
+  "response": {
+    "docs": [
+      {
+        "citation_title": "Obsolete entry test",
+        "citation_year": 2016,
+        "entry_author_list": ["Doe J"],
+        "journal": "J. Obs.",
+        "journal_page": "1-2",
+        "journal_volume": "1",
+        "pdb_id": "xxxx",
+        "status": "OBS",
+        "title": "OBSOLETE ENTRY TEST",
+        "superseded_by": "yyyy"
+      }
+    ],
+    "numFound": 1,
+    "start": 0
+  },
+  "responseHeader": {
+    "QTime": 0,
+    "params": {
+      "q": "xxxx",
+      "wt": "json"
+    },
+    "status": 0
+  }
+}
+"""
+        response = mock.Mock(text=json)
+        results = pdbe.response(response)
+        self.assertEqual(type(results), list)
+        self.assertEqual(len(results), 1)
+        self.assertEqual(results[0]['title'], 'OBSOLETE ENTRY TEST&nbsp;(OBSOLETE)')
+        self.assertTrue(results[0]['content'].startswith('<em>This entry has been superseded by'))

+ 51 - 0
tests/unit/engines/test_seedpeer.py

@@ -0,0 +1,51 @@
+import mock
+from collections import defaultdict
+from searx.engines import seedpeer
+from searx.testing import SearxTestCase
+from datetime import datetime
+
+
+class TestSeedPeerEngine(SearxTestCase):
+
+    html = ''
+    with open('./tests/unit/engines/seedpeer_fixture.html') as fixture:
+        html += fixture.read()
+
+    def test_request(self):
+        query = 'test_query'
+        dicto = defaultdict(dict)
+        dicto['pageno'] = 1
+        params = seedpeer.request(query, dicto)
+        self.assertIn('url', params)
+        self.assertIn(query, params['url'])
+        self.assertIn('seedpeer.eu', params['url'])
+
+    def test_response_raises_attr_error_on_empty_response(self):
+        self.assertRaises(AttributeError, seedpeer.response, None)
+        self.assertRaises(AttributeError, seedpeer.response, [])
+        self.assertRaises(AttributeError, seedpeer.response, '')
+        self.assertRaises(AttributeError, seedpeer.response, '[]')
+
+    def test_response_returns_empty_list(self):
+        response = mock.Mock(text='<html></html>')
+        self.assertEqual(seedpeer.response(response), [])
+
+    def test_response_returns_all_results(self):
+        response = mock.Mock(text=self.html)
+        results = seedpeer.response(response)
+        self.assertTrue(isinstance(results, list))
+        self.assertEqual(len(results), 2)
+
+    def test_response_returns_correct_results(self):
+        response = mock.Mock(text=self.html)
+        results = seedpeer.response(response)
+        self.assertEqual(
+            results[0]['title'], 'Narcos - Season 2 - 720p WEBRiP - x265 HEVC - ShAaNiG '
+        )
+        self.assertEqual(
+            results[0]['url'],
+            'http://www.seedpeer.eu/details/11685972/Narcos---Season-2---720p-WEBRiP---x265-HEVC---ShAaNiG.html'
+        )
+        self.assertEqual(results[0]['content'], '2.48 GB, 1 day')
+        self.assertEqual(results[0]['seed'], '861')
+        self.assertEqual(results[0]['leech'], '332')

+ 2 - 2
tests/unit/test_webapp.py

@@ -44,7 +44,7 @@ class ViewsTestCase(SearxTestCase):
         webapp.Search.search = search_mock
         webapp.Search.search = search_mock
 
 
         def get_current_theme_name_mock(override=None):
         def get_current_theme_name_mock(override=None):
-            return 'default'
+            return 'legacy'
 
 
         webapp.get_current_theme_name = get_current_theme_name_mock
         webapp.get_current_theme_name = get_current_theme_name_mock
 
 
@@ -58,7 +58,7 @@ class ViewsTestCase(SearxTestCase):
     def test_index_html(self):
     def test_index_html(self):
         result = self.app.post('/', data={'q': 'test'})
         result = self.app.post('/', data={'q': 'test'})
         self.assertIn(
         self.assertIn(
-            '<h3 class="result_title"><img width="14" height="14" class="favicon" src="/static/themes/default/img/icons/icon_youtube.ico" alt="youtube" /><a href="http://second.test.xyz" rel="noreferrer">Second <span class="highlight">Test</span></a></h3>',  # noqa
+            '<h3 class="result_title"><img width="14" height="14" class="favicon" src="/static/themes/legacy/img/icons/icon_youtube.ico" alt="youtube" /><a href="http://second.test.xyz" rel="noreferrer">Second <span class="highlight">Test</span></a></h3>',  # noqa
             result.data
             result.data
         )
         )
         self.assertIn(
         self.assertIn(

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