瀏覽代碼

Merge branch 'master' into http1.1

Alexandre Flament 8 年之前
父節點
當前提交
a88768efd8
共有 87 個檔案被更改,包括 624 行新增117 行删除
  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. 110
    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
   - npm
4
   - npm
5
   - directories:
5
   - directories:
6
     - $HOME/.cache/pip
6
     - $HOME/.cache/pip
7
+addons:
8
+  firefox: "latest"
7
 language: python
9
 language: python
8
 python:
10
 python:
9
   - "2.7"
11
   - "2.7"
12
   - "sh -e /etc/init.d/xvfb start"
14
   - "sh -e /etc/init.d/xvfb start"
13
   - npm install less grunt-cli
15
   - npm install less grunt-cli
14
   - ( cd searx/static/themes/oscar;npm install; cd - )
16
   - ( cd searx/static/themes/oscar;npm install; cd - )
17
+  - mkdir -p ~/drivers; export PATH=~/drivers:$PATH;
18
+  - GECKODRIVER_URL="https://github.com/mozilla/geckodriver/releases/download/v0.11.1/geckodriver-v0.11.1-linux64.tar.gz";
19
+  - FILE=`mktemp`; wget "$GECKODRIVER_URL" -qO $FILE && tar xz -C ~/drivers -f $FILE geckodriver; rm $FILE; chmod 777 ~/drivers/geckodriver;
15
 install:
20
 install:
16
   - ./manage.sh update_dev_packages
21
   - ./manage.sh update_dev_packages
17
   - pip install coveralls
22
   - pip install coveralls

+ 2
- 0
AUTHORS.rst 查看文件

58
 - marc @a01200356
58
 - marc @a01200356
59
 - Harry Wood @harry-wood
59
 - Harry Wood @harry-wood
60
 - Thomas Renard @threnard
60
 - Thomas Renard @threnard
61
+- Pydo `<https://github.com/pydo>`_
62
+- Athemis `<https://github.com/Athemis>`_

+ 2
- 2
manage.sh 查看文件

53
 
53
 
54
 styles() {
54
 styles() {
55
     echo '[!] Building styles'
55
     echo '[!] Building styles'
56
-	build_style themes/default/less/style.less themes/default/css/style.css
57
-	build_style themes/default/less/style-rtl.less themes/default/css/style-rtl.css
56
+	build_style themes/legacy/less/style.less themes/legacy/css/style.css
57
+	build_style themes/legacy/less/style-rtl.less themes/legacy/css/style-rtl.css
58
 	build_style themes/courgette/less/style.less themes/courgette/css/style.css
58
 	build_style themes/courgette/less/style.less themes/courgette/css/style.css
59
 	build_style themes/courgette/less/style-rtl.less themes/courgette/css/style-rtl.css
59
 	build_style themes/courgette/less/style-rtl.less themes/courgette/css/style-rtl.css
60
 	build_style less/bootstrap/bootstrap.less css/bootstrap.min.css
60
 	build_style less/bootstrap/bootstrap.less css/bootstrap.min.css

+ 3
- 3
requirements-dev.txt 查看文件

3
 nose2[coverage-plugin]
3
 nose2[coverage-plugin]
4
 pep8==1.7.0
4
 pep8==1.7.0
5
 plone.testing==5.0.0
5
 plone.testing==5.0.0
6
-robotframework-selenium2library==1.7.4
6
+robotframework-selenium2library==1.8.0
7
 robotsuite==1.7.0
7
 robotsuite==1.7.0
8
-transifex-client==0.11
8
+transifex-client==0.12.2
9
 unittest2==1.1.0
9
 unittest2==1.1.0
10
-zope.testrunner==4.4.10
10
+zope.testrunner==4.5.1

+ 1
- 1
requirements.txt 查看文件

1
-certifi==2016.2.28
1
+certifi==2016.9.26
2
 flask==0.11.1
2
 flask==0.11.1
3
 flask-babel==0.11.1
3
 flask-babel==0.11.1
4
 lxml==3.6.0
4
 lxml==3.6.0

+ 9
- 3
searx/engines/__init__.py 查看文件

57
 
57
 
58
 
58
 
59
 def load_engine(engine_data):
59
 def load_engine(engine_data):
60
-    engine_name = engine_data['engine']
60
+
61
+    if '_' in engine_data['name']:
62
+        logger.error('Engine name conains underscore: "{}"'.format(engine_data['name']))
63
+        sys.exit(1)
64
+
65
+    engine_module = engine_data['engine']
66
+
61
     try:
67
     try:
62
-        engine = load_module(engine_name + '.py')
68
+        engine = load_module(engine_module + '.py')
63
     except:
69
     except:
64
-        logger.exception('Cannot load engine "{}"'.format(engine_name))
70
+        logger.exception('Cannot load engine "{}"'.format(engine_module))
65
         return None
71
         return None
66
 
72
 
67
     for param_name in engine_data:
73
     for param_name in engine_data:

+ 1
- 1
searx/engines/digbt.py 查看文件

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

+ 11
- 35
searx/engines/kickass.py 查看文件

16
 from lxml import html
16
 from lxml import html
17
 from operator import itemgetter
17
 from operator import itemgetter
18
 from searx.engines.xpath import extract_text
18
 from searx.engines.xpath import extract_text
19
+from searx.utils import get_torrent_size, convert_str_to_int
19
 
20
 
20
 # engine dependent config
21
 # engine dependent config
21
 categories = ['videos', 'music', 'files']
22
 categories = ['videos', 'music', 'files']
22
 paging = True
23
 paging = True
23
 
24
 
24
 # search-url
25
 # search-url
25
-url = 'https://kickass.to/'
26
+url = 'https://kickass.cd/'
26
 search_url = url + 'search/{search_term}/{pageno}/'
27
 search_url = url + 'search/{search_term}/{pageno}/'
27
 
28
 
28
 # specific xpath variables
29
 # specific xpath variables
57
         href = urljoin(url, link.attrib['href'])
58
         href = urljoin(url, link.attrib['href'])
58
         title = extract_text(link)
59
         title = extract_text(link)
59
         content = escape(extract_text(result.xpath(content_xpath)))
60
         content = escape(extract_text(result.xpath(content_xpath)))
60
-        seed = result.xpath('.//td[contains(@class, "green")]/text()')[0]
61
-        leech = result.xpath('.//td[contains(@class, "red")]/text()')[0]
62
-        filesize = result.xpath('.//td[contains(@class, "nobr")]/text()')[0]
63
-        filesize_multiplier = result.xpath('.//td[contains(@class, "nobr")]//span/text()')[0]
64
-        files = result.xpath('.//td[contains(@class, "center")][2]/text()')[0]
65
-
66
-        # convert seed to int if possible
67
-        if seed.isdigit():
68
-            seed = int(seed)
69
-        else:
70
-            seed = 0
61
+        seed = extract_text(result.xpath('.//td[contains(@class, "green")]'))
62
+        leech = extract_text(result.xpath('.//td[contains(@class, "red")]'))
63
+        filesize_info = extract_text(result.xpath('.//td[contains(@class, "nobr")]'))
64
+        files = extract_text(result.xpath('.//td[contains(@class, "center")][2]'))
71
 
65
 
72
-        # convert leech to int if possible
73
-        if leech.isdigit():
74
-            leech = int(leech)
75
-        else:
76
-            leech = 0
77
-
78
-        # convert filesize to byte if possible
79
-        try:
80
-            filesize = float(filesize)
81
-
82
-            # convert filesize to byte
83
-            if filesize_multiplier == 'TB':
84
-                filesize = int(filesize * 1024 * 1024 * 1024 * 1024)
85
-            elif filesize_multiplier == 'GB':
86
-                filesize = int(filesize * 1024 * 1024 * 1024)
87
-            elif filesize_multiplier == 'MB':
88
-                filesize = int(filesize * 1024 * 1024)
89
-            elif filesize_multiplier == 'KB':
90
-                filesize = int(filesize * 1024)
91
-        except:
92
-            filesize = None
93
-
94
-        # convert files to int if possible
66
+        seed = convert_str_to_int(seed)
67
+        leech = convert_str_to_int(leech)
68
+
69
+        filesize, filesize_multiplier = filesize_info.split()
70
+        filesize = get_torrent_size(filesize, filesize_multiplier)
95
         if files.isdigit():
71
         if files.isdigit():
96
             files = int(files)
72
             files = int(files)
97
         else:
73
         else:

+ 109
- 0
searx/engines/pdbe.py 查看文件

1
+"""
2
+ PDBe (Protein Data Bank in Europe)
3
+
4
+ @website       https://www.ebi.ac.uk/pdbe
5
+ @provide-api   yes (https://www.ebi.ac.uk/pdbe/api/doc/search.html),
6
+                unlimited
7
+ @using-api     yes
8
+ @results       python dictionary (from json)
9
+ @stable        yes
10
+ @parse         url, title, content, img_src
11
+"""
12
+
13
+from json import loads
14
+from flask_babel import gettext
15
+
16
+categories = ['science']
17
+
18
+hide_obsolete = False
19
+
20
+# status codes of unpublished entries
21
+pdb_unpublished_codes = ['HPUB', 'HOLD', 'PROC', 'WAIT', 'AUTH', 'AUCO', 'REPL', 'POLC', 'REFI', 'TRSF', 'WDRN']
22
+# url for api query
23
+pdbe_solr_url = 'https://www.ebi.ac.uk/pdbe/search/pdb/select?'
24
+# base url for results
25
+pdbe_entry_url = 'https://www.ebi.ac.uk/pdbe/entry/pdb/{pdb_id}'
26
+# link to preview image of structure
27
+pdbe_preview_url = 'https://www.ebi.ac.uk/pdbe/static/entry/{pdb_id}_deposited_chain_front_image-200x200.png'
28
+
29
+
30
+def request(query, params):
31
+
32
+    params['url'] = pdbe_solr_url
33
+    params['method'] = 'POST'
34
+    params['data'] = {
35
+        'q': query,
36
+        'wt': "json"  # request response in parsable format
37
+    }
38
+    return params
39
+
40
+
41
+def construct_body(result):
42
+    # set title
43
+    title = result['title']
44
+
45
+    # construct content body
46
+    content = """{title}<br />{authors} {journal} <strong>{volume}</strong>&nbsp;{page} ({year})"""
47
+
48
+    # replace placeholders with actual content
49
+    try:
50
+        if result['journal']:
51
+            content = content.format(
52
+                title=result['citation_title'],
53
+                authors=result['entry_author_list'][0], journal=result['journal'], volume=result['journal_volume'],
54
+                page=result['journal_page'], year=result['citation_year'])
55
+        else:
56
+            content = content.format(
57
+                title=result['citation_title'],
58
+                authors=result['entry_author_list'][0], journal='', volume='', page='', year=result['release_year'])
59
+        img_src = pdbe_preview_url.format(pdb_id=result['pdb_id'])
60
+    except (KeyError):
61
+        content = None
62
+        img_src = None
63
+
64
+    # construct url for preview image
65
+    try:
66
+        img_src = pdbe_preview_url.format(pdb_id=result['pdb_id'])
67
+    except (KeyError):
68
+        img_src = None
69
+
70
+    return [title, content, img_src]
71
+
72
+
73
+def response(resp):
74
+
75
+    results = []
76
+    json = loads(resp.text)['response']['docs']
77
+
78
+    # parse results
79
+    for result in json:
80
+        # catch obsolete entries and mark them accordingly
81
+        if result['status'] in pdb_unpublished_codes:
82
+            continue
83
+        if hide_obsolete:
84
+            continue
85
+        if result['status'] == 'OBS':
86
+            # expand title to add some sort of warning message
87
+            title = gettext('{title}&nbsp;(OBSOLETE)').format(title=result['title'])
88
+            superseded_url = pdbe_entry_url.format(pdb_id=result['superseded_by'])
89
+
90
+            # since we can't construct a proper body from the response, we'll make up our own
91
+            msg_superseded = gettext("This entry has been superseded by")
92
+            content = '<em>{msg_superseded} \<a href="{url}">{pdb_id}</a></em>'.format(
93
+                msg_superseded=msg_superseded,
94
+                url=superseded_url,
95
+                pdb_id=result['superseded_by'], )
96
+
97
+            # obsoleted entries don't have preview images
98
+            img_src = None
99
+        else:
100
+            title, content, img_src = construct_body(result)
101
+
102
+        results.append({
103
+            'url': pdbe_entry_url.format(pdb_id=result['pdb_id']),
104
+            'title': title,
105
+            'content': content,
106
+            'img_src': img_src
107
+        })
108
+
109
+    return results

+ 78
- 0
searx/engines/seedpeer.py 查看文件

1
+#  Seedpeer (Videos, Music, Files)
2
+#
3
+# @website     http://seedpeer.eu
4
+# @provide-api no (nothing found)
5
+#
6
+# @using-api   no
7
+# @results     HTML (using search portal)
8
+# @stable      yes (HTML can change)
9
+# @parse       url, title, content, seed, leech, magnetlink
10
+
11
+from urlparse import urljoin
12
+from cgi import escape
13
+from urllib import quote
14
+from lxml import html
15
+from operator import itemgetter
16
+from searx.engines.xpath import extract_text
17
+
18
+
19
+url = 'http://www.seedpeer.eu/'
20
+search_url = url + 'search/{search_term}/7/{page_no}.html'
21
+# specific xpath variables
22
+torrent_xpath = '//*[@id="body"]/center/center/table[2]/tr/td/a'
23
+alternative_torrent_xpath = '//*[@id="body"]/center/center/table[1]/tr/td/a'
24
+title_xpath = '//*[@id="body"]/center/center/table[2]/tr/td/a/text()'
25
+alternative_title_xpath = '//*[@id="body"]/center/center/table/tr/td/a'
26
+seeds_xpath = '//*[@id="body"]/center/center/table[2]/tr/td[4]/font/text()'
27
+alternative_seeds_xpath = '//*[@id="body"]/center/center/table/tr/td[4]/font/text()'
28
+peers_xpath = '//*[@id="body"]/center/center/table[2]/tr/td[5]/font/text()'
29
+alternative_peers_xpath = '//*[@id="body"]/center/center/table/tr/td[5]/font/text()'
30
+age_xpath = '//*[@id="body"]/center/center/table[2]/tr/td[2]/text()'
31
+alternative_age_xpath = '//*[@id="body"]/center/center/table/tr/td[2]/text()'
32
+size_xpath = '//*[@id="body"]/center/center/table[2]/tr/td[3]/text()'
33
+alternative_size_xpath = '//*[@id="body"]/center/center/table/tr/td[3]/text()'
34
+
35
+
36
+# do search-request
37
+def request(query, params):
38
+    params['url'] = search_url.format(search_term=quote(query),
39
+                                      page_no=params['pageno'] - 1)
40
+    return params
41
+
42
+
43
+# get response from search-request
44
+def response(resp):
45
+    results = []
46
+    dom = html.fromstring(resp.text)
47
+    torrent_links = dom.xpath(torrent_xpath)
48
+    if len(torrent_links) > 0:
49
+        seeds = dom.xpath(seeds_xpath)
50
+        peers = dom.xpath(peers_xpath)
51
+        titles = dom.xpath(title_xpath)
52
+        sizes = dom.xpath(size_xpath)
53
+        ages = dom.xpath(age_xpath)
54
+    else:  # under ~5 results uses a different xpath
55
+        torrent_links = dom.xpath(alternative_torrent_xpath)
56
+        seeds = dom.xpath(alternative_seeds_xpath)
57
+        peers = dom.xpath(alternative_peers_xpath)
58
+        titles = dom.xpath(alternative_title_xpath)
59
+        sizes = dom.xpath(alternative_size_xpath)
60
+        ages = dom.xpath(alternative_age_xpath)
61
+    # return empty array if nothing is found
62
+    if not torrent_links:
63
+        return []
64
+
65
+    # parse results
66
+    for index, result in enumerate(torrent_links):
67
+        link = result.attrib.get('href')
68
+        href = urljoin(url, link)
69
+        results.append({'url': href,
70
+                        'title': titles[index].text_content(),
71
+                        'content': '{}, {}'.format(sizes[index], ages[index]),
72
+                        'seed': seeds[index],
73
+                        'leech': peers[index],
74
+
75
+                        'template': 'torrent.html'})
76
+
77
+    # return results sorted by seeder
78
+    return sorted(results, key=itemgetter('seed'), reverse=True)

+ 26
- 1
searx/settings.yml 查看文件

18
     default_theme : oscar # ui theme
18
     default_theme : oscar # ui theme
19
     default_locale : "" # Default interface locale - leave blank to detect from browser information or use codes from the 'locales' config section
19
     default_locale : "" # Default interface locale - leave blank to detect from browser information or use codes from the 'locales' config section
20
 
20
 
21
+# searx supports result proxification using an external service: https://github.com/asciimoo/morty
22
+# uncomment below section if you have running morty proxy
23
+#result_proxy:
24
+#    url : http://127.0.0.1:3000/
25
+#    key : your_morty_proxy_key
26
+
21
 outgoing: # communication with search engines
27
 outgoing: # communication with search engines
22
     request_timeout : 2.0 # seconds
28
     request_timeout : 2.0 # seconds
23
     useragent_suffix : "" # suffix of searx_useragent, could contain informations like an email address to the administrator
29
     useragent_suffix : "" # suffix of searx_useragent, could contain informations like an email address to the administrator
301
     timeout : 6.0
307
     timeout : 6.0
302
     disabled : True
308
     disabled : True
303
 
309
 
310
+  - name: kickass
311
+    engine : kickass
312
+    shortcut : kc
313
+    timeout : 4.0
314
+    disabled : True
315
+
304
   - name : microsoft academic
316
   - name : microsoft academic
305
     engine : json_engine
317
     engine : json_engine
306
     paging : True
318
     paging : True
339
     disabled : True
351
     disabled : True
340
     shortcut : or
352
     shortcut : or
341
 
353
 
354
+  - name : pdbe
355
+    engine : pdbe
356
+    shortcut : pdb
357
+# Hide obsolete PDB entries.
358
+# Default is not to hide obsolete structures
359
+#    hide_obsolete : False
360
+
342
   - name : photon
361
   - name : photon
343
     engine : photon
362
     engine : photon
344
     shortcut : ph
363
     shortcut : ph
377
     timeout : 10.0
396
     timeout : 10.0
378
     disabled : True
397
     disabled : True
379
 
398
 
380
-  - name : scanr_structures
399
+  - name : scanr structures
381
     shortcut: scs
400
     shortcut: scs
382
     engine : scanr_structures
401
     engine : scanr_structures
383
     disabled : True
402
     disabled : True
495
     timeout: 6.0
514
     timeout: 6.0
496
     categories : science
515
     categories : science
497
 
516
 
517
+  - name : seedpeer
518
+    engine : seedpeer
519
+    shortcut: speu
520
+    categories: files, music, videos
521
+    disabled: True
522
+
498
   - name : dictzone
523
   - name : dictzone
499
     engine : dictzone
524
     engine : dictzone
500
     shortcut : dc
525
     shortcut : dc

+ 3
- 3
searx/settings_robot.yml 查看文件

15
 
15
 
16
 ui:
16
 ui:
17
     themes_path : ""
17
     themes_path : ""
18
-    default_theme : default
18
+    default_theme : legacy
19
     default_locale : ""
19
     default_locale : ""
20
 
20
 
21
 outgoing:
21
 outgoing:
23
     useragent_suffix : ""
23
     useragent_suffix : ""
24
 
24
 
25
 engines:
25
 engines:
26
-  - name : general_dummy
26
+  - name : general dummy
27
     engine : dummy
27
     engine : dummy
28
     categories : general
28
     categories : general
29
     shortcut : gd
29
     shortcut : gd
30
 
30
 
31
-  - name : dummy_dummy
31
+  - name : dummy dummy
32
     engine : dummy
32
     engine : dummy
33
     categories : dummy
33
     categories : dummy
34
     shortcut : dd
34
     shortcut : dd

searx/static/themes/default/css/style-rtl.css → searx/static/themes/legacy/css/style-rtl.css 查看文件


searx/static/themes/default/css/style.css → searx/static/themes/legacy/css/style.css 查看文件


searx/static/themes/default/img/favicon.png → searx/static/themes/legacy/img/favicon.png 查看文件


searx/static/themes/default/img/github_ribbon.png → searx/static/themes/legacy/img/github_ribbon.png 查看文件


searx/static/themes/default/img/icons/icon_500px.ico → searx/static/themes/legacy/img/icons/icon_500px.ico 查看文件


searx/static/themes/default/img/icons/icon_bing.ico → searx/static/themes/legacy/img/icons/icon_bing.ico 查看文件


searx/static/themes/default/img/icons/icon_dailymotion.ico → searx/static/themes/legacy/img/icons/icon_dailymotion.ico 查看文件


searx/static/themes/default/img/icons/icon_deezer.ico → searx/static/themes/legacy/img/icons/icon_deezer.ico 查看文件


searx/static/themes/default/img/icons/icon_deviantart.ico → searx/static/themes/legacy/img/icons/icon_deviantart.ico 查看文件


searx/static/themes/default/img/icons/icon_digg.ico → searx/static/themes/legacy/img/icons/icon_digg.ico 查看文件


searx/static/themes/default/img/icons/icon_duckduckgo.ico → searx/static/themes/legacy/img/icons/icon_duckduckgo.ico 查看文件


searx/static/themes/default/img/icons/icon_flickr.ico → searx/static/themes/legacy/img/icons/icon_flickr.ico 查看文件


searx/static/themes/default/img/icons/icon_github.ico → searx/static/themes/legacy/img/icons/icon_github.ico 查看文件


searx/static/themes/default/img/icons/icon_google play apps.ico → searx/static/themes/legacy/img/icons/icon_google play apps.ico 查看文件


searx/static/themes/default/img/icons/icon_google play movies.ico → searx/static/themes/legacy/img/icons/icon_google play movies.ico 查看文件


searx/static/themes/default/img/icons/icon_google play music.ico → searx/static/themes/legacy/img/icons/icon_google play music.ico 查看文件


searx/static/themes/default/img/icons/icon_google.ico → searx/static/themes/legacy/img/icons/icon_google.ico 查看文件


searx/static/themes/default/img/icons/icon_kickass.ico → searx/static/themes/legacy/img/icons/icon_kickass.ico 查看文件


searx/static/themes/default/img/icons/icon_openstreetmap.ico → searx/static/themes/legacy/img/icons/icon_openstreetmap.ico 查看文件


searx/static/themes/default/img/icons/icon_searchcode code.ico → searx/static/themes/legacy/img/icons/icon_searchcode code.ico 查看文件


searx/static/themes/default/img/icons/icon_searchcode doc.ico → searx/static/themes/legacy/img/icons/icon_searchcode doc.ico 查看文件


searx/static/themes/default/img/icons/icon_searchcode.ico → searx/static/themes/legacy/img/icons/icon_searchcode.ico 查看文件


searx/static/themes/default/img/icons/icon_soundcloud.ico → searx/static/themes/legacy/img/icons/icon_soundcloud.ico 查看文件


searx/static/themes/default/img/icons/icon_stackoverflow.ico → searx/static/themes/legacy/img/icons/icon_stackoverflow.ico 查看文件


searx/static/themes/default/img/icons/icon_startpage.ico → searx/static/themes/legacy/img/icons/icon_startpage.ico 查看文件


searx/static/themes/default/img/icons/icon_subtitleseeker.ico → searx/static/themes/legacy/img/icons/icon_subtitleseeker.ico 查看文件


searx/static/themes/default/img/icons/icon_twitter.ico → searx/static/themes/legacy/img/icons/icon_twitter.ico 查看文件


searx/static/themes/default/img/icons/icon_vimeo.ico → searx/static/themes/legacy/img/icons/icon_vimeo.ico 查看文件


searx/static/themes/default/img/icons/icon_wikipedia.ico → searx/static/themes/legacy/img/icons/icon_wikipedia.ico 查看文件


searx/static/themes/default/img/icons/icon_yahoo.ico → searx/static/themes/legacy/img/icons/icon_yahoo.ico 查看文件


searx/static/themes/default/img/icons/icon_youtube.ico → searx/static/themes/legacy/img/icons/icon_youtube.ico 查看文件


searx/static/themes/default/img/preference-icon.png → searx/static/themes/legacy/img/preference-icon.png 查看文件


searx/static/themes/default/img/search-icon.png → searx/static/themes/legacy/img/search-icon.png 查看文件


searx/static/themes/default/img/searx.png → searx/static/themes/legacy/img/searx.png 查看文件


searx/static/themes/default/img/searx_logo.svg → searx/static/themes/legacy/img/searx_logo.svg 查看文件


searx/static/themes/default/js/searx.js → searx/static/themes/legacy/js/searx.js 查看文件


searx/static/themes/default/less/autocompleter.less → searx/static/themes/legacy/less/autocompleter.less 查看文件


searx/static/themes/default/less/code.less → searx/static/themes/legacy/less/code.less 查看文件


searx/static/themes/default/less/definitions.less → searx/static/themes/legacy/less/definitions.less 查看文件


searx/static/themes/default/less/mixins.less → searx/static/themes/legacy/less/mixins.less 查看文件


searx/static/themes/default/less/search.less → searx/static/themes/legacy/less/search.less 查看文件


searx/static/themes/default/less/style-rtl.less → searx/static/themes/legacy/less/style-rtl.less 查看文件


searx/static/themes/default/less/style.less → searx/static/themes/legacy/less/style.less 查看文件


+ 1
- 1
searx/templates/courgette/base.html 查看文件

22
         {% endblock %}
22
         {% endblock %}
23
         {% block meta %}{% endblock %}
23
         {% block meta %}{% endblock %}
24
         {% block head %}
24
         {% block head %}
25
-        <link title="searx" type="application/opensearchdescription+xml" rel="search" href="{{ url_for('opensearch') }}"/>
25
+        <link title="{{ instance_name }}" type="application/opensearchdescription+xml" rel="search" href="{{ url_for('opensearch') }}"/>
26
         {% endblock %}
26
         {% endblock %}
27
         <script type="text/javascript">
27
         <script type="text/javascript">
28
             searx = {};
28
             searx = {};

searx/templates/default/404.html → searx/templates/legacy/404.html 查看文件

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

searx/templates/default/about.html → searx/templates/legacy/about.html 查看文件

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

searx/templates/default/base.html → searx/templates/legacy/base.html 查看文件

17
         {% endblock %}
17
         {% endblock %}
18
         {% block meta %}{% endblock %}
18
         {% block meta %}{% endblock %}
19
         {% block head %}
19
         {% block head %}
20
-        <link title="searx" type="application/opensearchdescription+xml" rel="search" href="{{ url_for('opensearch') }}"/>
20
+        <link title="{{ instance_name }}" type="application/opensearchdescription+xml" rel="search" href="{{ url_for('opensearch') }}"/>
21
         {% endblock %}
21
         {% endblock %}
22
     </head>
22
     </head>
23
     <body>
23
     <body>

searx/templates/default/categories.html → searx/templates/legacy/categories.html 查看文件


searx/templates/default/github_ribbon.html → searx/templates/legacy/github_ribbon.html 查看文件


searx/templates/default/index.html → searx/templates/legacy/index.html 查看文件

1
-{% extends "default/base.html" %}
1
+{% extends "legacy/base.html" %}
2
 {% block content %}
2
 {% block content %}
3
 <div class="center">
3
 <div class="center">
4
     <div class="title"><h1>searx</h1></div>
4
     <div class="title"><h1>searx</h1></div>
5
-    {% include 'default/search.html' %}
5
+    {% include 'legacy/search.html' %}
6
     <p class="top_margin">
6
     <p class="top_margin">
7
     	{% if rtl %}
7
     	{% if rtl %}
8
     	<a href="{{ url_for('preferences') }}" class="hmarg">{{ _('preferences') }}</a>
8
     	<a href="{{ url_for('preferences') }}" class="hmarg">{{ _('preferences') }}</a>
13
         {% endif %}
13
         {% endif %}
14
     </p>
14
     </p>
15
 </div>
15
 </div>
16
-{% include 'default/github_ribbon.html' %}
16
+{% include 'legacy/github_ribbon.html' %}
17
 {% endblock %}
17
 {% endblock %}
18
 
18
 

searx/templates/default/infobox.html → searx/templates/legacy/infobox.html 查看文件


searx/templates/default/opensearch.xml → searx/templates/legacy/opensearch.xml 查看文件


searx/templates/default/opensearch_response_rss.xml → searx/templates/legacy/opensearch_response_rss.xml 查看文件


searx/templates/default/preferences.html → searx/templates/legacy/preferences.html 查看文件

1
-{% extends "default/base.html" %}
1
+{% extends "legacy/base.html" %}
2
 {% block head %} {% endblock %}
2
 {% block head %} {% endblock %}
3
 {% block content %}
3
 {% block content %}
4
 <div class="row">
4
 <div class="row">
8
     <fieldset>
8
     <fieldset>
9
         <legend>{{ _('Default categories') }}</legend>
9
         <legend>{{ _('Default categories') }}</legend>
10
         {% set display_tooltip = false %}
10
         {% set display_tooltip = false %}
11
-        {% include 'default/categories.html' %}
11
+        {% include 'legacy/categories.html' %}
12
     </fieldset>
12
     </fieldset>
13
     <fieldset>
13
     <fieldset>
14
         <legend>{{ _('Search language') }}</legend>
14
         <legend>{{ _('Search language') }}</legend>

searx/templates/default/result_templates/code.html → searx/templates/legacy/result_templates/code.html 查看文件


searx/templates/default/result_templates/default.html → searx/templates/legacy/result_templates/default.html 查看文件


searx/templates/default/result_templates/images.html → searx/templates/legacy/result_templates/images.html 查看文件


searx/templates/default/result_templates/map.html → searx/templates/legacy/result_templates/map.html 查看文件


searx/templates/default/result_templates/torrent.html → searx/templates/legacy/result_templates/torrent.html 查看文件


searx/templates/default/result_templates/videos.html → searx/templates/legacy/result_templates/videos.html 查看文件


searx/templates/default/results.html → searx/templates/legacy/results.html 查看文件

1
-{% extends "default/base.html" %}
1
+{% extends "legacy/base.html" %}
2
 {% block title %}{{ q }} - {% endblock %}
2
 {% block title %}{{ q }} - {% endblock %}
3
 {% 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 %}
3
 {% 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 %}
4
 {% block content %}
4
 {% block content %}
5
 <div class="preferences_container right"><a href="{{ url_for('preferences') }}" id="preferences"><span>preferences</span></a></div>
5
 <div class="preferences_container right"><a href="{{ url_for('preferences') }}" id="preferences"><span>preferences</span></a></div>
6
 <div class="small search center">
6
 <div class="small search center">
7
-    {% include 'default/search.html' %}
7
+    {% include 'legacy/search.html' %}
8
 </div>
8
 </div>
9
 <div id="results">
9
 <div id="results">
10
     <div id="sidebar">
10
     <div id="sidebar">
55
     {% if infoboxes %}
55
     {% if infoboxes %}
56
     <div id="infoboxes">
56
     <div id="infoboxes">
57
       {% for infobox in infoboxes %}
57
       {% for infobox in infoboxes %}
58
-         {% include 'default/infobox.html' %}
58
+         {% include 'legacy/infobox.html' %}
59
       {% endfor %}
59
       {% endfor %}
60
     </div>
60
     </div>
61
     {% endif %}
61
     {% endif %}
62
 
62
 
63
     {% for result in results %}
63
     {% for result in results %}
64
         {% if result['template'] %}
64
         {% if result['template'] %}
65
-            {% include get_result_template('default', result['template']) %}
65
+            {% include get_result_template('legacy', result['template']) %}
66
         {% else %}
66
         {% else %}
67
-            {% include 'default/result_templates/default.html' %}
67
+            {% include 'legacy/result_templates/default.html' %}
68
         {% endif %}
68
         {% endif %}
69
     {% endfor %}
69
     {% endfor %}
70
 
70
 

searx/templates/default/search.html → searx/templates/legacy/search.html 查看文件

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

searx/templates/default/stats.html → searx/templates/legacy/stats.html 查看文件

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

+ 6
- 0
searx/templates/oscar/macros.html 查看文件

33
         <span class="label label-default">{{ engine }}</span>
33
         <span class="label label-default">{{ engine }}</span>
34
     {% endfor %}
34
     {% endfor %}
35
     <small>{{ result_link("https://web.archive.org/web/" + result.url, icon('link') + _('cached'), "text-info") }}</small>
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 %}
36
 </div>
39
 </div>
37
     <div class="text-muted"><small>{{ result.pretty_url }}</small></div>
40
     <div class="text-muted"><small>{{ result.pretty_url }}</small></div>
38
 {%- endmacro %}
41
 {%- endmacro %}
44
         <span class="label label-default">{{ engine }}</span>
47
         <span class="label label-default">{{ engine }}</span>
45
     {% endfor %}
48
     {% endfor %}
46
     <small>{{ result_link("https://web.archive.org/web/" + result.url, icon('link') + _('cached'), "text-info") }}</small>
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 %}
47
     <div class="text-muted"><small>{{ result.pretty_url }}</small></div>
53
     <div class="text-muted"><small>{{ result.pretty_url }}</small></div>
48
 {%- endmacro %}
54
 {%- endmacro %}
49
 
55
 

+ 1
- 1
searx/templates/pix-art/preferences.html 查看文件

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

+ 1
- 1
searx/templates/pix-art/stats.html 查看文件

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

+ 15
- 0
searx/utils.py 查看文件

252
             filesize = int(filesize * 1024 * 1024)
252
             filesize = int(filesize * 1024 * 1024)
253
         elif filesize_multiplier == 'KB':
253
         elif filesize_multiplier == 'KB':
254
             filesize = int(filesize * 1024)
254
             filesize = int(filesize * 1024)
255
+        elif filesize_multiplier == 'TiB':
256
+            filesize = int(filesize * 1000 * 1000 * 1000 * 1000)
257
+        elif filesize_multiplier == 'GiB':
258
+            filesize = int(filesize * 1000 * 1000 * 1000)
259
+        elif filesize_multiplier == 'MiB':
260
+            filesize = int(filesize * 1000 * 1000)
261
+        elif filesize_multiplier == 'KiB':
262
+            filesize = int(filesize * 1000)
255
     except:
263
     except:
256
         filesize = None
264
         filesize = None
257
 
265
 
258
     return filesize
266
     return filesize
259
 
267
 
260
 
268
 
269
+def convert_str_to_int(number_str):
270
+    if number_str.isdigit():
271
+        return int(number_str)
272
+    else:
273
+        return 0
274
+
275
+
261
 def is_valid_lang(lang):
276
 def is_valid_lang(lang):
262
     is_abbr = (len(lang) == 2)
277
     is_abbr = (len(lang) == 2)
263
     if is_abbr:
278
     if is_abbr:

+ 22
- 5
searx/webapp.py 查看文件

22
     from os.path import realpath, dirname
22
     from os.path import realpath, dirname
23
     path.append(realpath(dirname(realpath(__file__)) + '/../'))
23
     path.append(realpath(dirname(realpath(__file__)) + '/../'))
24
 
24
 
25
-import json
26
 import cStringIO
25
 import cStringIO
27
-import os
28
 import hashlib
26
 import hashlib
27
+import hmac
28
+import json
29
+import os
29
 import requests
30
 import requests
30
 
31
 
31
 from searx import logger
32
 from searx import logger
245
     return url_for(endpoint, **values)
246
     return url_for(endpoint, **values)
246
 
247
 
247
 
248
 
249
+def proxify(url):
250
+    if url.startswith('//'):
251
+        url = 'https:' + url
252
+
253
+    if not settings.get('result_proxy'):
254
+        return url
255
+
256
+    h = hmac.new(settings['result_proxy']['key'], url.encode('utf-8'), hashlib.sha256).hexdigest()
257
+
258
+    return '{0}?{1}'.format(settings['result_proxy']['url'],
259
+                            urlencode(dict(mortyurl=url.encode('utf-8'),
260
+                                           mortyhash=h)))
261
+
262
+
248
 def image_proxify(url):
263
 def image_proxify(url):
249
 
264
 
250
     if url.startswith('//'):
265
     if url.startswith('//'):
253
     if not request.preferences.get_value('image_proxy'):
268
     if not request.preferences.get_value('image_proxy'):
254
         return url
269
         return url
255
 
270
 
256
-    hash_string = url + settings['server']['secret_key']
257
-    h = hashlib.sha256(hash_string.encode('utf-8')).hexdigest()
271
+    h = hmac.new(settings['server']['secret_key'], url.encode('utf-8'), hashlib.sha256).hexdigest()
258
 
272
 
259
     return '{0}?{1}'.format(url_for('image_proxy'),
273
     return '{0}?{1}'.format(url_for('image_proxy'),
260
                             urlencode(dict(url=url.encode('utf-8'), h=h)))
274
                             urlencode(dict(url=url.encode('utf-8'), h=h)))
313
 
327
 
314
     kwargs['image_proxify'] = image_proxify
328
     kwargs['image_proxify'] = image_proxify
315
 
329
 
330
+    kwargs['proxify'] = proxify if settings.get('result_proxy') else None
331
+
316
     kwargs['get_result_template'] = get_result_template
332
     kwargs['get_result_template'] = get_result_template
317
 
333
 
318
     kwargs['theme'] = get_current_theme_name(override=override_theme)
334
     kwargs['theme'] = get_current_theme_name(override=override_theme)
602
     if not url:
618
     if not url:
603
         return '', 400
619
         return '', 400
604
 
620
 
605
-    h = hashlib.sha256(url + settings['server']['secret_key'].encode('utf-8')).hexdigest()
621
+    h = hmac.new(settings['server']['secret_key'], url, hashlib.sha256).hexdigest()
606
 
622
 
607
     if h != request.args.get('h'):
623
     if h != request.args.get('h'):
608
         return '', 400
624
         return '', 400
660
 Allow: /about
676
 Allow: /about
661
 Disallow: /stats
677
 Disallow: /stats
662
 Disallow: /preferences
678
 Disallow: /preferences
679
+Disallow: /*?*q=*
663
 """, mimetype='text/plain')
680
 """, mimetype='text/plain')
664
 
681
 
665
 
682
 

+ 24
- 28
tests/robot/test_basic.robot 查看文件

4
 Test Teardown   Close All Browsers
4
 Test Teardown   Close All Browsers
5
 
5
 
6
 
6
 
7
+*** Keywords ***
8
+Submit Preferences
9
+    Set Selenium Speed  2 seconds
10
+    Submit Form  id=search_form
11
+    Location Should Be  http://localhost:11111/
12
+    Set Selenium Speed  0 seconds
13
+
14
+
7
 *** Test Cases ***
15
 *** Test Cases ***
8
 Front page
16
 Front page
9
     Page Should Contain  about
17
     Page Should Contain  about
24
     Page Should Contain  Preferences
32
     Page Should Contain  Preferences
25
     Page Should Contain  Default categories
33
     Page Should Contain  Default categories
26
     Page Should Contain  Currently used search engines
34
     Page Should Contain  Currently used search engines
27
-    Page Should Contain  dummy_dummy
28
-    Page Should Contain  general_dummy
35
+    Page Should Contain  dummy dummy
36
+    Page Should Contain  general dummy
29
 
37
 
30
 Switch category
38
 Switch category
31
     Go To  http://localhost:11111/preferences
39
     Go To  http://localhost:11111/preferences
33
     Page Should Contain Checkbox  category_dummy
41
     Page Should Contain Checkbox  category_dummy
34
     Click Element  xpath=//*[.="general"]
42
     Click Element  xpath=//*[.="general"]
35
     Click Element  xpath=//*[.="dummy"]
43
     Click Element  xpath=//*[.="dummy"]
36
-    Submit Form  id=search_form
37
-    Location Should Be  http://localhost:11111/
44
+    Submit Preferences
38
     Checkbox Should Not Be Selected  category_general
45
     Checkbox Should Not Be Selected  category_general
39
     Checkbox Should Be Selected  category_dummy
46
     Checkbox Should Be Selected  category_dummy
40
 
47
 
43
     Page Should Contain  preferences
50
     Page Should Contain  preferences
44
     Go To  http://localhost:11111/preferences
51
     Go To  http://localhost:11111/preferences
45
     Select From List  locale  hu
52
     Select From List  locale  hu
46
-    Submit Form  id=search_form
47
-    Location Should Be  http://localhost:11111/
53
+    Submit Preferences
48
     Page Should Contain  rólunk
54
     Page Should Contain  rólunk
49
     Page Should Contain  beállítások
55
     Page Should Contain  beállítások
50
 
56
 
53
     Page Should Contain  preferences
59
     Page Should Contain  preferences
54
     Go To  http://localhost:11111/preferences
60
     Go To  http://localhost:11111/preferences
55
     Select From List  method  GET
61
     Select From List  method  GET
56
-    Submit Form  id=search_form
57
-    Location Should Be  http://localhost:11111/
62
+    Submit Preferences
58
     Go To  http://localhost:11111/preferences
63
     Go To  http://localhost:11111/preferences
59
     List Selection Should Be  method  GET
64
     List Selection Should Be  method  GET
60
     Select From List  method  POST
65
     Select From List  method  POST
61
-    Submit Form  id=search_form
62
-    Location Should Be  http://localhost:11111/
66
+    Submit Preferences
63
     Go To  http://localhost:11111/preferences
67
     Go To  http://localhost:11111/preferences
64
     List Selection Should Be  method  POST
68
     List Selection Should Be  method  POST
65
 
69
 
67
     Page Should Contain  about
71
     Page Should Contain  about
68
     Page Should Contain  preferences
72
     Page Should Contain  preferences
69
     Go To  http://localhost:11111/preferences
73
     Go To  http://localhost:11111/preferences
70
-    List Selection Should Be  theme  default
74
+    List Selection Should Be  theme  legacy
71
     Select From List  theme  oscar
75
     Select From List  theme  oscar
72
-    Submit Form  id=search_form
73
-    Location Should Be  http://localhost:11111/
76
+    Submit Preferences
74
     Go To  http://localhost:11111/preferences
77
     Go To  http://localhost:11111/preferences
75
     List Selection Should Be  theme  oscar
78
     List Selection Should Be  theme  oscar
76
 
79
 
80
     Go To  http://localhost:11111/preferences
83
     Go To  http://localhost:11111/preferences
81
     List Selection Should Be  safesearch  None
84
     List Selection Should Be  safesearch  None
82
     Select From List  safesearch  Strict
85
     Select From List  safesearch  Strict
83
-    Submit Form  id=search_form
84
-    Location Should Be  http://localhost:11111/
86
+    Submit Preferences
85
     Go To  http://localhost:11111/preferences
87
     Go To  http://localhost:11111/preferences
86
     List Selection Should Be  safesearch  Strict
88
     List Selection Should Be  safesearch  Strict
87
 
89
 
91
     Go To  http://localhost:11111/preferences
93
     Go To  http://localhost:11111/preferences
92
     List Selection Should Be  image_proxy  Disabled
94
     List Selection Should Be  image_proxy  Disabled
93
     Select From List  image_proxy  Enabled
95
     Select From List  image_proxy  Enabled
94
-    Submit Form  id=search_form
95
-    Location Should Be  http://localhost:11111/
96
+    Submit Preferences
96
     Go To  http://localhost:11111/preferences
97
     Go To  http://localhost:11111/preferences
97
     List Selection Should Be  image_proxy  Enabled
98
     List Selection Should Be  image_proxy  Enabled
98
 
99
 
102
     Go To  http://localhost:11111/preferences
103
     Go To  http://localhost:11111/preferences
103
     List Selection Should Be  language  Automatic
104
     List Selection Should Be  language  Automatic
104
     Select From List  language  Turkish (Turkey) - tr_TR
105
     Select From List  language  Turkish (Turkey) - tr_TR
105
-    Submit Form  id=search_form
106
-    Location Should Be  http://localhost:11111/
106
+    Submit Preferences
107
     Go To  http://localhost:11111/preferences
107
     Go To  http://localhost:11111/preferences
108
     List Selection Should Be  language  Turkish (Turkey) - tr_TR
108
     List Selection Should Be  language  Turkish (Turkey) - tr_TR
109
 
109
 
113
     Go To  http://localhost:11111/preferences
113
     Go To  http://localhost:11111/preferences
114
     List Selection Should Be  autocomplete  -
114
     List Selection Should Be  autocomplete  -
115
     Select From List  autocomplete  google
115
     Select From List  autocomplete  google
116
-    Submit Form  id=search_form
117
-    Location Should Be  http://localhost:11111/
116
+    Submit Preferences
118
     Go To  http://localhost:11111/preferences
117
     Go To  http://localhost:11111/preferences
119
     List Selection Should Be  autocomplete  google
118
     List Selection Should Be  autocomplete  google
120
 
119
 
126
     Element Should Contain  xpath=//label[@class="deny"][@for='engine_dummy_dummy_dummy']  Block
125
     Element Should Contain  xpath=//label[@class="deny"][@for='engine_dummy_dummy_dummy']  Block
127
     Element Should Contain  xpath=//label[@class="deny"][@for='engine_general_general_dummy']  Block
126
     Element Should Contain  xpath=//label[@class="deny"][@for='engine_general_general_dummy']  Block
128
     Click Element  xpath=//label[@class="deny"][@for='engine_general_general_dummy']
127
     Click Element  xpath=//label[@class="deny"][@for='engine_general_general_dummy']
129
-    Submit Form  id=search_form
130
-    Location Should Be  http://localhost:11111/
128
+    Submit Preferences
131
     Page Should Contain  about
129
     Page Should Contain  about
132
     Page Should Contain  preferences
130
     Page Should Contain  preferences
133
     Go To  http://localhost:11111/preferences
131
     Go To  http://localhost:11111/preferences
139
     Page Should Contain  about
137
     Page Should Contain  about
140
     Page Should Contain  preferences
138
     Page Should Contain  preferences
141
     Go To  http://localhost:11111/preferences
139
     Go To  http://localhost:11111/preferences
142
-    List Selection Should Be  theme  default
140
+    List Selection Should Be  theme  legacy
143
     Select From List  theme  oscar
141
     Select From List  theme  oscar
144
-    Submit Form  id=search_form
145
-    Location Should Be  http://localhost:11111/
142
+    Submit Preferences
146
     Go To  http://localhost:11111/preferences
143
     Go To  http://localhost:11111/preferences
147
     List Selection Should Be  theme  oscar
144
     List Selection Should Be  theme  oscar
148
     Page Should Contain  Plugins
145
     Page Should Contain  Plugins
149
     Click Link  Plugins
146
     Click Link  Plugins
150
     Checkbox Should Not Be Selected  id=plugin_HTTPS_rewrite
147
     Checkbox Should Not Be Selected  id=plugin_HTTPS_rewrite
151
     Click Element  xpath=//label[@for='plugin_HTTPS_rewrite']
148
     Click Element  xpath=//label[@for='plugin_HTTPS_rewrite']
152
-    Submit Form  id=search_form
153
-    Location Should Be  http://localhost:11111/
149
+    Submit Preferences
154
     Go To  http://localhost:11111/preferences
150
     Go To  http://localhost:11111/preferences
155
     Page Should Contain  Plugins
151
     Page Should Contain  Plugins
156
     Click Link  Plugins
152
     Click Link  Plugins

+ 110
- 0
tests/unit/engines/seedpeer_fixture.html 查看文件

1
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
+        <html xmlns="http://www.w3.org/1999/xhtml">
3
+        <head>
4
+        </head>
5
+        <body>
6
+            <div id="header">
7
+                <div id="whoIsYou">
8
+                        <a href="/lang.php"><small>SeedPeer in your own language?</small></a>&nbsp;&nbsp;&nbsp;<a href="http://www.seedpeer.eu"><img src="/images/flags/uk.gif" width="16px" alt="Torrents EN" /></a> <a href="http://spanish.seedpeer.eu"><img src="/images/flags/es.gif" width="16px" alt="Torrents ES" /></a> <a href="http://german.seedpeer.eu"><img src="/images/flags/de.gif" width="16px" alt="Torrents DE" /></a> <a href="http://french.seedpeer.eu"><img src="/images/flags/fr.gif" width="16px" alt="Torrents FR" /></a> <a href="http://portuguese.seedpeer.eu"><img src="/images/flags/pt.gif" width="16px" alt="Torrents Portuguese" /></a> <a href="http://swedish.seedpeer.eu"><img src="/images/flags/se.gif" width="16px" alt="Torrents Sweden" /></a>
9
+                        </div>
10
+
11
+                <script type="text/javascript">
12
+                whoIsYou();
13
+                </script>
14
+                    <div id="search">
15
+                        <form action="/search.php" method="get">
16
+                            <input id="topsearchbar" name="search" value="narcos season 2" />
17
+                            <input type="submit" class="searchbutton" value="Torrents" />
18
+                            <input style="color:#000" type="submit" class="searchbutton" name="usenet" value="Usenet Binaries" />
19
+                        </form>
20
+                        <div id="suggestion"></div>
21
+                    </div>
22
+                    <div id="logo"><a href="/"><img src="/images/logo2.gif" alt="Seedpeer homepage" width="415" height="143" /></a></div>
23
+                    <div id="subtext"><a href="/">Home</a> &gt; <a href="/search.html">Torrent search</a> &gt; Narcos season 2 | page 1</div>
24
+            </div>
25
+        <div id="nav">
26
+            <ul>
27
+        <!--
28
+                <li><font style="color:red;font-size:9px;font-weight:bold;">NEW</font><a title="Download TOP Games for FREE" rel="nofollow" href="http://www.bigrebelads.com/affiliate/index?ref=9301" target="_blank">FREE Games</a></li>
29
+
30
+        -->
31
+                <li style="border-left:none" id="categories"><a title="Browse Torrent Categories" href="/browse.html">Categories</a>
32
+                    <ul>
33
+                        <li><a title="Browse Anime Torrents" href="/browse.html#6">Anime</a></li>
34
+                        <li><a title="Browse Game Torrents" href="/browse.html#4">Games</a></li>
35
+                        <li><a title="Browse Movie Torrents" href="/browse.html#1">Movies</a></li>
36
+                        <li><a title="Browse Music Torrents" href="/browse.html#3">Music</a></li>
37
+                        <li><a title="Browse Software Torrents" href="/browse.html#5">Software</a></li>
38
+                        <li><a title="Browse TV Torrents" href="/browse.html#2">TV Shows</a></li>
39
+                        <li><a title="Browse Other Torrents" href="/browse.html#7">Others</a></li>
40
+                    </ul>
41
+                    </li>
42
+                        <li><a title="Upload A Torrents" href="/upload.html">Upload torrent</a></li>
43
+                        <li id="verified"><a title="Verified Torrents" href="/verified.html">Verified</a></li>
44
+                        <li id="searchoptions"><a title="Search Torrents" href="/search.html">Torrent search</a></li>
45
+                        <li id="newsgroups"><a style="color:#212b3e" title="News Groups" href="/usenet.html">Usenet Binaries</a></li>
46
+                        <li id="about" style="border-right:none"><a rel="nofollow" href="/faq.html">About Us</a>
47
+                    <ul>
48
+                        <li><a title="SeedPeer Statistics" href="/stats.html">Statistics</a></li>
49
+                        <li><a title="Contact Us" href="/contact.html">Contact</a></li>
50
+                        <li><a title="Frequently  Asked Questions" href="/faq.html">FAQ</a></li>
51
+                        <li><a title="SeedPeer API" href="http://api.seedpeer.eu">Our API</a></li>
52
+                        <li><a title="SeedPeer Blog" href="/blog">Blog</a></li>
53
+                    </ul>
54
+                    </li>
55
+                    <!--<li><a href="/toolbar.php">Our Toolbar</a></li>-->
56
+                </ul>
57
+            <div class="clear"></div>
58
+        </div>
59
+        <div id="body"><div id="pageTop"></div>
60
+        <div id="headerbox"><h1>Verified <font class="colored">Narcos season 2</font> torrents</h1></div><table width="100%"><tr><th>
61
+        <span style="float:right">
62
+        <a href="/search/narcos-season-2/8/1.html"><img style="vertical-align:middle" src="/images/comments.gif" alt="comments" /></a> |
63
+        <a href="/search/narcos-season-2/7/1.html"><img style="vertical-align:middle" src="/images/ver.gif" alt="verified" /></a>
64
+        </span>
65
+        <a href="/search/narcos-season-2/1/1.html">Torrent name</a></th><th class="right"><a href="/search/narcos-season-2/2/1.html">Age</a></th><th class="right"><a href="/search/narcos-season-2/3/1.html">Size</a></th><th class="right"><a href="/search/narcos-season-2/4/1.html">Seeds</a></th><th class="right"><a href="/search/narcos-season-2/5/1.html">Peers</a></th><th class="center"><a href="/search/narcos-season-2/6/1.html">Health</a></th><td class="tableAd" rowspan="6"><iframe src="http://creative.wwwpromoter.com/13689?d=300x250" width="300" height="250" style="border: none;" frameborder="0" scrolling="no"></iframe></td></tr><tr class=""><td><a class="pblink" id="pblink_table_item_1" href="" data-tad="431726" data-last-search="narcos+season+2" target="_blank" rel="nofollow"><strong class='colored'>Narcos season 2</strong> Full Version</a></td><td class="right">20 hours</td><td class="right">681.3 MB</td><td class="right"><font color="green">28</font> </td><td class="right"><font color="navy">654</font> </td><td class="center"><img src="/images/h5.gif" alt="Health" /></td></tr><tr class="tdark"><td><a class="pblink" id="pblink_table_item_2" href="" data-tad="431727" data-url="narcos+season+2" target="_blank" rel="nofollow"><strong class='colored'>Narcos season 2</strong> Trusted Source</a></td><td class="right">12 hours</td><td class="right">787.1 MB</td><td class="right"><font color="green">64</font> </td><td class="right"><font color="navy">220</font> </td><td class="center"><img src="/images/h5.gif" alt="Health" /></td></tr><tr class=""><td><a class="pblink" id="pblink_table_item_3" href="" data-tad="431729" data-last-search="narcos+season+2" target="_blank" rel="nofollow"><strong class='colored'>Full Narcos season 2 Download</strong></a> <small><a class="pblink" id="pblink_table_item_4" href="" data-tad="431729" data-last-search="narcos+season+2" target="_blank" rel="nofollow">Usenet</a></small></td><td class="right">24 hours</td><td class="right">775.5 MB</td><td class="right"><font color="green">60</font> </td><td class="right"><font color="navy">236</font> </td><td class="center"><img src="/images/h5.gif" alt="Health" /></td></tr><tr class="tdark"><td><a class="pblink" id="pblink_table_item_5" href="" data-tad="431730" data-last-search="narcos+season+2" target="_blank" rel="nofollow"><strong class='colored'>Narcos season 2</strong> 2014 - DIRECT STREAMING</a> <small><a class="pblink" id="pblink_table_item_6" href="" data-tad="431729" data-last-search="narcos+season+2" target="_blank" rel="nofollow">Movies</a></small></td><td class="right">17 hours</td><td class="right">654.1 MB</td><td class="right"><font color="green">2</font> </td><td class="right"><font color="navy">391</font> </td><td class="center"><img src="/images/h5.gif" alt="Health" /></td></tr><tr class=""><td><a class="pblink" id="pblink_table_item_7" href="" data-tad="431731" data-last-search="narcos+season+2" target="_blank" rel="nofollow"><strong class='colored'>Narcos season 2</strong> 2014</a> <small><a class="pblink" id="pblink_table_item_8" href="" data-tad="431729" data-last-search="narcos+season+2" target="_blank" rel="nofollow">Movies</a></small></td><td class="right">20 hours</td><td class="right">754.5 MB</td><td class="right"><font color="green">21</font> </td><td class="right"><font color="navy">919</font> </td><td class="center"><img src="/images/h5.gif" alt="Health" /></td></tr></table><br /><br /><center><iframe src='http://creative.wwwpromoter.com/13689?d=728x90' width='728' height='90' style='border: none;' frameborder='0' scrolling='no'></iframe><center><span style="float:right;margin:1em .2em 0 0"><a title="Download at the speed of your connection" href="/usenet.php?search=narcos+season+2"><img src="/images/dlf.gif" alt="Search Binaries" /></a></span><div style="margin-bottom:1em;margin-right:290px" id="headerbox"><h1><a href="/searchfeed/narcos+season+2.xml" target="_blank" title="SeedPeer RSS Torrent Search Feed fornarcos season 2"><img src="/images/feedIcon.png" border="0" /></a>&nbsp;2 <font class="colored">Narcos season 2</font> Torrents were found</h1></div><table width="100%"><tr><th>
66
+        <span style="float:right">
67
+        <a href="/search/narcos-season-2/8/1.html"><img style="vertical-align:middle" src="/images/comments.gif" alt="comments" /></a> |
68
+        <a href="/search/narcos-season-2/7/1.html"><img style="vertical-align:middle" src="/images/ver.gif" alt="verified" /></a>
69
+        </span>
70
+        <a href="/search/narcos-season-2/1/1.html">Torrent name</a></th><th class="right"><a href="/search/narcos-season-2/2/1.html">Age</a></th><th class="right"><a href="/search/narcos-season-2/3/1.html">Size</a></th><th class="right"><a href="/search/narcos-season-2/4/1.html">Seeds</a></th><th class="right"><a href="/search/narcos-season-2/5/1.html">Peers</a></th><th class="center"><a href="/search/narcos-season-2/6/1.html">Health</a></th></tr><tr class=""><td><small class="comments"><a href="http://www.facebook.com/sharer.php?t=Download%20<strong class='colored'>Narcos</strong> <strong class='colored'>Season</strong> <strong class='colored'>2</strong> Complete 7<strong class='colored'>2</strong>0p WebRip EN-SUB x<strong class='colored'>2</strong>64-[MULVAcoded] S0<strong class='colored'>2</strong>%20 torrent&u=http://seedpeer.seedpeer.eu/details/11686840/Narcos-Season-2-Complete-720p-WebRip-EN-SUB-x264-[MULVAcoded]-S02.html"><img src="/images/facebook.png" alt="Add to Facebook" width="14" height="14" /></a></small><a href="/details/11686840/Narcos-Season-2-Complete-720p-WebRip-EN-SUB-x264-[MULVAcoded]-S02.html"><strong class='colored'>Narcos</strong> <strong class='colored'>Season</strong> <strong class='colored'>2</strong> Complete 7<strong class='colored'>2</strong>0p WebRip EN-SUB x<strong class='colored'>2</strong>64-[MULVAcoded] S0<strong class='colored'>2</strong> <small><a href="/browse.html#11686840"></a></small></a></td><td class="right">19 hours</td><td class="right">4.39 GB</td><td class="right"><font color="green">715</font> </td><td class="right"><font color="navy">183</font> </td><td class="center"><img src="/images/h5.gif" alt="Health" width="40" height="11" /></td></tr><tr class="tdark"><td><small class="comments"><a href="http://www.facebook.com/sharer.php?t=Download%20<strong class='colored'>Narcos</strong> - <strong class='colored'>Season</strong> <strong class='colored'>2</strong> - 7<strong class='colored'>2</strong>0p WEBRiP - x<strong class='colored'>2</strong>65 HEVC - ShAaNiG%20 torrent&u=http://seedpeer.seedpeer.eu/details/11685972/Narcos---Season-2---720p-WEBRiP---x265-HEVC---ShAaNiG.html"><img src="/images/facebook.png" alt="Add to Facebook" width="14" height="14" /></a></small><a href="/details/11685972/Narcos---Season-2---720p-WEBRiP---x265-HEVC---ShAaNiG.html"><strong class='colored'>Narcos</strong> - <strong class='colored'>Season</strong> <strong class='colored'>2</strong> - 7<strong class='colored'>2</strong>0p WEBRiP - x<strong class='colored'>2</strong>65 HEVC - ShAaNiG <small><a href="/browse.html#11685972"></a></small></a></td><td class="right">1 day</td><td class="right">2.48 GB</td><td class="right"><font color="green">861</font> </td><td class="right"><font color="navy">332</font> </td><td class="center"><img src="/images/h5.gif" alt="Health" width="40" height="11" /></td></tr></table><div id="headerbox"><h1>Related searches for: <font class="colored">Narcos season 2</font></h1></div><div id="search_suggestions"><br />Other suggested searches: </div><br /><a href="http://torrentz2.eu/search?f=narcos-season-2">Search for "narcos-season-2" on Torrentz2.eu</a><br /><a href="http://torrent-finder.info/show.php?q=narcos-season-2">Search for "narcos-season-2" on Torrent-Finder</a><br /><center><iframe src='http://creative.wwwpromoter.com/13689?d=300x250' width='300' height='250' style='border: none;' frameborder='0' scrolling='no'></iframe>&nbsp;<iframe src='http://creative.wwwpromoter.com/13689?d=300x250' width='300' height='250' style='border: none;' frameborder='0' scrolling='no'></iframe>&nbsp;<iframe src='http://creative.wwwpromoter.com/13689?d=300x250' width='300' height='250' style='border: none;' frameborder='0' scrolling='no'></iframe></center><div id="footer">
71
+        <table width="100%">
72
+        <tr>
73
+        <td width="30%">
74
+        <h2>Torrents Download</h2>
75
+        <a href="/">Torrent search</a><br />
76
+        <a href="/browse.html">Browse categories</a><br />
77
+        <a href="/verified.html">Verified Torrents</a><br />
78
+        <a href="/order-date.html">Today's torrents</a><br />
79
+        <a href="/yesterday.html">Yesterday's torrents</a><br />
80
+        <a href="/stats.html">Statistics</a><br />
81
+        <br />
82
+        <a href="/faq.html#copyright"><strong>Copyright & Removal</strong></a>
83
+        </td>
84
+        <td width="30%"><h2>Cool Stuff</h2>
85
+        <a href="/promotional.php">Promotional</a><br />
86
+        <a href="/contact.html">Advertising Information</a><br />
87
+        <strong><a href="/plugins.php" title="Add a search plugin to Firefox or Internet Explorer">Search Plugin <span style="color:red">*</span></a></strong><br />
88
+        <a href="http://www.utorrent.com">&micro;Torrent Client</a><br />
89
+        <a href="/blog">Seedpeer Blog</a><br />
90
+        </td>
91
+        <td width="30%"><h2>Links</h2>
92
+         <a href="http://www.sumotorrent.com" target="_blank"><strong>SumoTorrent</strong></a><br />
93
+         <a href="http://www.torrent-finder.info" target="_blank"><strong>Torrent Finder</strong></a><br />
94
+         <a href="http://www.torrentpond.com" target="_blank"><strong>TorrentPond</strong></a><br />
95
+         <a href="https://www.limetorrents.cc" target="_blank">LimeTorrents.cc</a><br />
96
+         <a href="http://www.torrents.to/" target="_blank">Torrents.to</a><br />
97
+         <a href="http://www.torrentfunk.com" target="_blank">TorrentFunk</a><br />
98
+         <a href="https://monova.org" target="_blank">Monova</a><br />
99
+         <a href="http://www.torrentroom.com" target="_blank">TorrentRoom</a><br />
100
+         <a href="http://www.katcr.co/" target="_blank">Kickass Torrents Community</a><br />
101
+        </td>
102
+        <td width="10%"><div id="bottomlogo"></div></td>
103
+        </tr>
104
+        </table>
105
+        <br />
106
+        <br />
107
+        </div>
108
+        </div>
109
+        </body>
110
+        </html>

+ 3
- 1
tests/unit/engines/test_digbt.py 查看文件

28
         <table class="table">
28
         <table class="table">
29
             <tr><td class="x-item">
29
             <tr><td class="x-item">
30
             <div>
30
             <div>
31
-                <a title="The Big Bang Theory" class="title" href="/The-Big-Bang-Theory-d2.html">The Big Bang Theory</a>
31
+                <a title="The Big Bang Theory" class="title" href="/The-Big-Bang-Theory-d2.html">
32
+                    The Big <span class="highlight">Bang</span> Theory
33
+                </a>
32
                 <span class="ctime"><span style="color:red;">4 hours ago</span></span>
34
                 <span class="ctime"><span style="color:red;">4 hours ago</span></span>
33
             </div>
35
             </div>
34
             <div class="files">
36
             <div class="files">

+ 13
- 13
tests/unit/engines/test_kickass.py 查看文件

14
         params = kickass.request(query, dicto)
14
         params = kickass.request(query, dicto)
15
         self.assertIn('url', params)
15
         self.assertIn('url', params)
16
         self.assertIn(query, params['url'])
16
         self.assertIn(query, params['url'])
17
-        self.assertIn('kickass.to', params['url'])
17
+        self.assertIn('kickass.cd', params['url'])
18
         self.assertFalse(params['verify'])
18
         self.assertFalse(params['verify'])
19
 
19
 
20
     def test_response(self):
20
     def test_response(self):
84
                         </span>
84
                         </span>
85
                     </div>
85
                     </div>
86
                 </td>
86
                 </td>
87
-                <td class="nobr center">449 <span>bytes</span></td>
87
+                <td class="nobr center">449 bytes</td>
88
                 <td class="center">4</td>
88
                 <td class="center">4</td>
89
                 <td class="center">2&nbsp;years</td>
89
                 <td class="center">2&nbsp;years</td>
90
                 <td class="green center">10</td>
90
                 <td class="green center">10</td>
97
         self.assertEqual(type(results), list)
97
         self.assertEqual(type(results), list)
98
         self.assertEqual(len(results), 1)
98
         self.assertEqual(len(results), 1)
99
         self.assertEqual(results[0]['title'], 'This should be the title')
99
         self.assertEqual(results[0]['title'], 'This should be the title')
100
-        self.assertEqual(results[0]['url'], 'https://kickass.to/url.html')
100
+        self.assertEqual(results[0]['url'], 'https://kickass.cd/url.html')
101
         self.assertEqual(results[0]['content'], 'Posted by riri in Other &gt; Unsorted')
101
         self.assertEqual(results[0]['content'], 'Posted by riri in Other &gt; Unsorted')
102
         self.assertEqual(results[0]['seed'], 10)
102
         self.assertEqual(results[0]['seed'], 10)
103
         self.assertEqual(results[0]['leech'], 1)
103
         self.assertEqual(results[0]['leech'], 1)
191
                         </span>
191
                         </span>
192
                     </div>
192
                     </div>
193
                 </td>
193
                 </td>
194
-                <td class="nobr center">1 <span>KB</span></td>
194
+                <td class="nobr center">1 KiB</td>
195
                 <td class="center">4</td>
195
                 <td class="center">4</td>
196
                 <td class="center">2&nbsp;years</td>
196
                 <td class="center">2&nbsp;years</td>
197
                 <td class="green center">10</td>
197
                 <td class="green center">10</td>
235
                         </span>
235
                         </span>
236
                     </div>
236
                     </div>
237
                 </td>
237
                 </td>
238
-                <td class="nobr center">1 <span>MB</span></td>
238
+                <td class="nobr center">1 MiB</td>
239
                 <td class="center">4</td>
239
                 <td class="center">4</td>
240
                 <td class="center">2&nbsp;years</td>
240
                 <td class="center">2&nbsp;years</td>
241
                 <td class="green center">9</td>
241
                 <td class="green center">9</td>
279
                         </span>
279
                         </span>
280
                     </div>
280
                     </div>
281
                 </td>
281
                 </td>
282
-                <td class="nobr center">1 <span>GB</span></td>
282
+                <td class="nobr center">1 GiB</td>
283
                 <td class="center">4</td>
283
                 <td class="center">4</td>
284
                 <td class="center">2&nbsp;years</td>
284
                 <td class="center">2&nbsp;years</td>
285
                 <td class="green center">8</td>
285
                 <td class="green center">8</td>
323
                         </span>
323
                         </span>
324
                     </div>
324
                     </div>
325
                 </td>
325
                 </td>
326
-                <td class="nobr center">1 <span>TB</span></td>
326
+                <td class="nobr center">1 TiB</td>
327
                 <td class="center">4</td>
327
                 <td class="center">4</td>
328
                 <td class="center">2&nbsp;years</td>
328
                 <td class="center">2&nbsp;years</td>
329
                 <td class="green center">7</td>
329
                 <td class="green center">7</td>
367
                         </span>
367
                         </span>
368
                     </div>
368
                     </div>
369
                 </td>
369
                 </td>
370
-                <td class="nobr center">z <span>bytes</span></td>
370
+                <td class="nobr center">z bytes</td>
371
                 <td class="center">r</td>
371
                 <td class="center">r</td>
372
                 <td class="center">2&nbsp;years</td>
372
                 <td class="center">2&nbsp;years</td>
373
                 <td class="green center">a</td>
373
                 <td class="green center">a</td>
380
         self.assertEqual(type(results), list)
380
         self.assertEqual(type(results), list)
381
         self.assertEqual(len(results), 5)
381
         self.assertEqual(len(results), 5)
382
         self.assertEqual(results[0]['title'], 'This should be the title')
382
         self.assertEqual(results[0]['title'], 'This should be the title')
383
-        self.assertEqual(results[0]['url'], 'https://kickass.to/url.html')
383
+        self.assertEqual(results[0]['url'], 'https://kickass.cd/url.html')
384
         self.assertEqual(results[0]['content'], 'Posted by riri in Other &gt; Unsorted')
384
         self.assertEqual(results[0]['content'], 'Posted by riri in Other &gt; Unsorted')
385
         self.assertEqual(results[0]['seed'], 10)
385
         self.assertEqual(results[0]['seed'], 10)
386
         self.assertEqual(results[0]['leech'], 1)
386
         self.assertEqual(results[0]['leech'], 1)
387
         self.assertEqual(results[0]['files'], 4)
387
         self.assertEqual(results[0]['files'], 4)
388
         self.assertEqual(results[0]['magnetlink'], 'magnet:?xt=urn:btih:MAGNETURL&dn=test')
388
         self.assertEqual(results[0]['magnetlink'], 'magnet:?xt=urn:btih:MAGNETURL&dn=test')
389
         self.assertEqual(results[0]['torrentfile'], 'http://torcache.net/torrent/53917.torrent?title=test')
389
         self.assertEqual(results[0]['torrentfile'], 'http://torcache.net/torrent/53917.torrent?title=test')
390
-        self.assertEqual(results[0]['filesize'], 1024)
391
-        self.assertEqual(results[1]['filesize'], 1048576)
392
-        self.assertEqual(results[2]['filesize'], 1073741824)
393
-        self.assertEqual(results[3]['filesize'], 1099511627776)
390
+        self.assertEqual(results[0]['filesize'], 1000)
391
+        self.assertEqual(results[1]['filesize'], 1000000)
392
+        self.assertEqual(results[2]['filesize'], 1000000000)
393
+        self.assertEqual(results[3]['filesize'], 1000000000000)
394
         self.assertEqual(results[4]['seed'], 0)
394
         self.assertEqual(results[4]['seed'], 0)
395
         self.assertEqual(results[4]['leech'], 0)
395
         self.assertEqual(results[4]['leech'], 0)
396
         self.assertEqual(results[4]['files'], None)
396
         self.assertEqual(results[4]['files'], None)

+ 109
- 0
tests/unit/engines/test_pdbe.py 查看文件

1
+import mock
2
+from collections import defaultdict
3
+from searx.engines import pdbe
4
+from searx.testing import SearxTestCase
5
+
6
+
7
+class TestPdbeEngine(SearxTestCase):
8
+    def test_request(self):
9
+        query = 'test_query'
10
+        dicto = defaultdict(dict)
11
+        params = pdbe.request(query, dicto)
12
+        self.assertTrue('url' in params)
13
+        self.assertTrue('ebi.ac.uk' in params['url'])
14
+        self.assertTrue('data' in params)
15
+        self.assertTrue('q' in params['data'])
16
+        self.assertTrue(query in params['data']['q'])
17
+        self.assertTrue('wt' in params['data'])
18
+        self.assertTrue('json' in params['data']['wt'])
19
+        self.assertTrue('method' in params)
20
+        self.assertTrue(params['method'] == 'POST')
21
+
22
+    def test_response(self):
23
+        self.assertRaises(AttributeError, pdbe.response, None)
24
+        self.assertRaises(AttributeError, pdbe.response, [])
25
+        self.assertRaises(AttributeError, pdbe.response, '')
26
+        self.assertRaises(AttributeError, pdbe.response, '[]')
27
+
28
+        json = """
29
+{
30
+  "response": {
31
+    "docs": [
32
+      {
33
+        "citation_title": "X-ray crystal structure of ferric Aplysia limacina myoglobin in different liganded states.",
34
+        "citation_year": 1993,
35
+        "entry_author_list": [
36
+          "Conti E, Moser C, Rizzi M, Mattevi A, Lionetti C, Coda A, Ascenzi P, Brunori M, Bolognesi M"
37
+        ],
38
+        "journal": "J. Mol. Biol.",
39
+        "journal_page": "498-508",
40
+        "journal_volume": "233",
41
+        "pdb_id": "2fal",
42
+        "status": "REL",
43
+        "title": "X-RAY CRYSTAL STRUCTURE OF FERRIC APLYSIA LIMACINA MYOGLOBIN IN DIFFERENT LIGANDED STATES"
44
+      }
45
+    ],
46
+    "numFound": 1,
47
+    "start": 0
48
+  },
49
+  "responseHeader": {
50
+    "QTime": 0,
51
+    "params": {
52
+      "q": "2fal",
53
+      "wt": "json"
54
+    },
55
+    "status": 0
56
+  }
57
+}
58
+"""
59
+
60
+        response = mock.Mock(text=json)
61
+        results = pdbe.response(response)
62
+        self.assertEqual(type(results), list)
63
+        self.assertEqual(len(results), 1)
64
+        self.assertEqual(results[0]['title'],
65
+                         'X-RAY CRYSTAL STRUCTURE OF FERRIC APLYSIA LIMACINA MYOGLOBIN IN DIFFERENT LIGANDED STATES')
66
+        self.assertEqual(results[0]['url'], pdbe.pdbe_entry_url.format(pdb_id='2fal'))
67
+        self.assertEqual(results[0]['img_src'], pdbe.pdbe_preview_url.format(pdb_id='2fal'))
68
+        self.assertTrue('Conti E' in results[0]['content'])
69
+        self.assertTrue('X-ray crystal structure of ferric Aplysia limacina myoglobin in different liganded states.' in
70
+                        results[0]['content'])
71
+        self.assertTrue('1993' in results[0]['content'])
72
+
73
+        # Testing proper handling of PDB entries marked as obsolete
74
+        json = """
75
+{
76
+  "response": {
77
+    "docs": [
78
+      {
79
+        "citation_title": "Obsolete entry test",
80
+        "citation_year": 2016,
81
+        "entry_author_list": ["Doe J"],
82
+        "journal": "J. Obs.",
83
+        "journal_page": "1-2",
84
+        "journal_volume": "1",
85
+        "pdb_id": "xxxx",
86
+        "status": "OBS",
87
+        "title": "OBSOLETE ENTRY TEST",
88
+        "superseded_by": "yyyy"
89
+      }
90
+    ],
91
+    "numFound": 1,
92
+    "start": 0
93
+  },
94
+  "responseHeader": {
95
+    "QTime": 0,
96
+    "params": {
97
+      "q": "xxxx",
98
+      "wt": "json"
99
+    },
100
+    "status": 0
101
+  }
102
+}
103
+"""
104
+        response = mock.Mock(text=json)
105
+        results = pdbe.response(response)
106
+        self.assertEqual(type(results), list)
107
+        self.assertEqual(len(results), 1)
108
+        self.assertEqual(results[0]['title'], 'OBSOLETE ENTRY TEST&nbsp;(OBSOLETE)')
109
+        self.assertTrue(results[0]['content'].startswith('<em>This entry has been superseded by'))

+ 51
- 0
tests/unit/engines/test_seedpeer.py 查看文件

1
+import mock
2
+from collections import defaultdict
3
+from searx.engines import seedpeer
4
+from searx.testing import SearxTestCase
5
+from datetime import datetime
6
+
7
+
8
+class TestSeedPeerEngine(SearxTestCase):
9
+
10
+    html = ''
11
+    with open('./tests/unit/engines/seedpeer_fixture.html') as fixture:
12
+        html += fixture.read()
13
+
14
+    def test_request(self):
15
+        query = 'test_query'
16
+        dicto = defaultdict(dict)
17
+        dicto['pageno'] = 1
18
+        params = seedpeer.request(query, dicto)
19
+        self.assertIn('url', params)
20
+        self.assertIn(query, params['url'])
21
+        self.assertIn('seedpeer.eu', params['url'])
22
+
23
+    def test_response_raises_attr_error_on_empty_response(self):
24
+        self.assertRaises(AttributeError, seedpeer.response, None)
25
+        self.assertRaises(AttributeError, seedpeer.response, [])
26
+        self.assertRaises(AttributeError, seedpeer.response, '')
27
+        self.assertRaises(AttributeError, seedpeer.response, '[]')
28
+
29
+    def test_response_returns_empty_list(self):
30
+        response = mock.Mock(text='<html></html>')
31
+        self.assertEqual(seedpeer.response(response), [])
32
+
33
+    def test_response_returns_all_results(self):
34
+        response = mock.Mock(text=self.html)
35
+        results = seedpeer.response(response)
36
+        self.assertTrue(isinstance(results, list))
37
+        self.assertEqual(len(results), 2)
38
+
39
+    def test_response_returns_correct_results(self):
40
+        response = mock.Mock(text=self.html)
41
+        results = seedpeer.response(response)
42
+        self.assertEqual(
43
+            results[0]['title'], 'Narcos - Season 2 - 720p WEBRiP - x265 HEVC - ShAaNiG '
44
+        )
45
+        self.assertEqual(
46
+            results[0]['url'],
47
+            'http://www.seedpeer.eu/details/11685972/Narcos---Season-2---720p-WEBRiP---x265-HEVC---ShAaNiG.html'
48
+        )
49
+        self.assertEqual(results[0]['content'], '2.48 GB, 1 day')
50
+        self.assertEqual(results[0]['seed'], '861')
51
+        self.assertEqual(results[0]['leech'], '332')

+ 2
- 2
tests/unit/test_webapp.py 查看文件

44
         webapp.Search.search = search_mock
44
         webapp.Search.search = search_mock
45
 
45
 
46
         def get_current_theme_name_mock(override=None):
46
         def get_current_theme_name_mock(override=None):
47
-            return 'default'
47
+            return 'legacy'
48
 
48
 
49
         webapp.get_current_theme_name = get_current_theme_name_mock
49
         webapp.get_current_theme_name = get_current_theme_name_mock
50
 
50
 
58
     def test_index_html(self):
58
     def test_index_html(self):
59
         result = self.app.post('/', data={'q': 'test'})
59
         result = self.app.post('/', data={'q': 'test'})
60
         self.assertIn(
60
         self.assertIn(
61
-            '<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
61
+            '<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
62
             result.data
62
             result.data
63
         )
63
         )
64
         self.assertIn(
64
         self.assertIn(