Merge branch 'master' into http1.1
| 
						 | 
					@ -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
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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>`_
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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/legacy/less/style.less themes/legacy/css/style.css
 | 
				
			||||||
	build_style themes/default/less/style-rtl.less themes/default/css/style-rtl.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,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,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
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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])
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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]
 | 
					        seed = extract_text(result.xpath('.//td[contains(@class, "green")]'))
 | 
				
			||||||
        leech = result.xpath('.//td[contains(@class, "red")]/text()')[0]
 | 
					        leech = extract_text(result.xpath('.//td[contains(@class, "red")]'))
 | 
				
			||||||
        filesize = result.xpath('.//td[contains(@class, "nobr")]/text()')[0]
 | 
					        filesize_info = extract_text(result.xpath('.//td[contains(@class, "nobr")]'))
 | 
				
			||||||
        filesize_multiplier = result.xpath('.//td[contains(@class, "nobr")]//span/text()')[0]
 | 
					        files = extract_text(result.xpath('.//td[contains(@class, "center")][2]'))
 | 
				
			||||||
        files = result.xpath('.//td[contains(@class, "center")][2]/text()')[0]
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # convert seed to int if possible
 | 
					        seed = convert_str_to_int(seed)
 | 
				
			||||||
        if seed.isdigit():
 | 
					        leech = convert_str_to_int(leech)
 | 
				
			||||||
            seed = int(seed)
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            seed = 0
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # convert leech to int if possible
 | 
					        filesize, filesize_multiplier = filesize_info.split()
 | 
				
			||||||
        if leech.isdigit():
 | 
					        filesize = get_torrent_size(filesize, filesize_multiplier)
 | 
				
			||||||
            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
 | 
					 | 
				
			||||||
        if files.isdigit():
 | 
					        if files.isdigit():
 | 
				
			||||||
            files = int(files)
 | 
					            files = int(files)
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										109
									
								
								searx/engines/pdbe.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -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> {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} (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
									
								
								searx/engines/seedpeer.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -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)
 | 
				
			||||||
| 
						 | 
					@ -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
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
		 Before Width: | Height: | Size: 2 KiB After Width: | Height: | Size: 2 KiB  | 
| 
		 Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.1 KiB  | 
| 
		 Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 8.2 KiB  | 
| 
		 Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB  | 
| 
		 Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB  | 
| 
		 Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB  | 
| 
		 Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB  | 
| 
		 Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB  | 
| 
		 Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB  | 
| 
		 Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.4 KiB  | 
| 
		 Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.4 KiB  | 
| 
		 Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB  | 
| 
		 Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB  | 
| 
		 Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB  | 
| 
		 Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB  | 
| 
		 Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB  | 
| 
		 Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB  | 
| 
		 Before Width: | Height: | Size: 4 KiB After Width: | Height: | Size: 4 KiB  | 
| 
		 Before Width: | Height: | Size: 4 KiB After Width: | Height: | Size: 4 KiB  | 
| 
		 Before Width: | Height: | Size: 4 KiB After Width: | Height: | Size: 4 KiB  | 
| 
		 Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB  | 
| 
		 Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB  | 
| 
		 Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB  | 
| 
		 Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB  | 
| 
		 Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB  | 
| 
		 Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.4 KiB  | 
| 
		 Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB  | 
| 
		 Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB  | 
| 
		 Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB  | 
| 
		 Before Width: | Height: | Size: 532 B After Width: | Height: | Size: 532 B  | 
| 
		 Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB  | 
| 
		 Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB  | 
| 
		 Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.1 KiB  | 
| 
						 | 
					@ -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,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>
 | 
				
			||||||
| 
						 | 
					@ -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>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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>
 | 
				
			||||||
| 
						 | 
					@ -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 %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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>
 | 
				
			||||||
| 
						 | 
					@ -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 }}&format=rss&{% for category in selected_categories %}category_{{ category }}=1&{% endfor %}pageno={{ pageno }}">{% endblock %}
 | 
					{% block meta %}<link rel="alternate" type="application/rss+xml" title="Searx search: {{ q }}" href="{{ url_for('index') }}?q={{ q|urlencode }}&format=rss&{% for category in selected_categories %}category_{{ category }}=1&{% 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 %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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,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>
 | 
				
			||||||
| 
						 | 
					@ -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,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,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>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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,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 = hmac.new(settings['server']['secret_key'], url.encode('utf-8'), hashlib.sha256).hexdigest()
 | 
				
			||||||
    h = hashlib.sha256(hash_string.encode('utf-8')).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')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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  dummy dummy
 | 
				
			||||||
    Page Should Contain  general_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
 | 
					    Submit Preferences
 | 
				
			||||||
    Location Should Be  http://localhost:11111/
 | 
					 | 
				
			||||||
    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
 | 
					    Submit Preferences
 | 
				
			||||||
    Location Should Be  http://localhost:11111/
 | 
					 | 
				
			||||||
    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
 | 
					    Submit Preferences
 | 
				
			||||||
    Location Should Be  http://localhost:11111/
 | 
					 | 
				
			||||||
    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
 | 
					    Submit Preferences
 | 
				
			||||||
    Location Should Be  http://localhost:11111/
 | 
					 | 
				
			||||||
    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
 | 
					    Submit Preferences
 | 
				
			||||||
    Location Should Be  http://localhost:11111/
 | 
					 | 
				
			||||||
    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
 | 
					    Submit Preferences
 | 
				
			||||||
    Location Should Be  http://localhost:11111/
 | 
					 | 
				
			||||||
    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
 | 
					    Submit Preferences
 | 
				
			||||||
    Location Should Be  http://localhost:11111/
 | 
					 | 
				
			||||||
    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
 | 
					    Submit Preferences
 | 
				
			||||||
    Location Should Be  http://localhost:11111/
 | 
					 | 
				
			||||||
    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
 | 
					    Submit Preferences
 | 
				
			||||||
    Location Should Be  http://localhost:11111/
 | 
					 | 
				
			||||||
    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
 | 
					    Submit Preferences
 | 
				
			||||||
    Location Should Be  http://localhost:11111/
 | 
					 | 
				
			||||||
    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
 | 
					    Submit Preferences
 | 
				
			||||||
    Location Should Be  http://localhost:11111/
 | 
					 | 
				
			||||||
    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
 | 
					    Submit Preferences
 | 
				
			||||||
    Location Should Be  http://localhost:11111/
 | 
					 | 
				
			||||||
    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
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										110
									
								
								tests/unit/engines/seedpeer_fixture.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,110 @@
 | 
				
			||||||
 | 
					<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 | 
				
			||||||
 | 
					        <html xmlns="http://www.w3.org/1999/xhtml">
 | 
				
			||||||
 | 
					        <head>
 | 
				
			||||||
 | 
					        </head>
 | 
				
			||||||
 | 
					        <body>
 | 
				
			||||||
 | 
					            <div id="header">
 | 
				
			||||||
 | 
					                <div id="whoIsYou">
 | 
				
			||||||
 | 
					                        <a href="/lang.php"><small>SeedPeer in your own language?</small></a>   <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>
 | 
				
			||||||
 | 
					                        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <script type="text/javascript">
 | 
				
			||||||
 | 
					                whoIsYou();
 | 
				
			||||||
 | 
					                </script>
 | 
				
			||||||
 | 
					                    <div id="search">
 | 
				
			||||||
 | 
					                        <form action="/search.php" method="get">
 | 
				
			||||||
 | 
					                            <input id="topsearchbar" name="search" value="narcos season 2" />
 | 
				
			||||||
 | 
					                            <input type="submit" class="searchbutton" value="Torrents" />
 | 
				
			||||||
 | 
					                            <input style="color:#000" type="submit" class="searchbutton" name="usenet" value="Usenet Binaries" />
 | 
				
			||||||
 | 
					                        </form>
 | 
				
			||||||
 | 
					                        <div id="suggestion"></div>
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                    <div id="logo"><a href="/"><img src="/images/logo2.gif" alt="Seedpeer homepage" width="415" height="143" /></a></div>
 | 
				
			||||||
 | 
					                    <div id="subtext"><a href="/">Home</a> > <a href="/search.html">Torrent search</a> > Narcos season 2 | page 1</div>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					        <div id="nav">
 | 
				
			||||||
 | 
					            <ul>
 | 
				
			||||||
 | 
					        <!--
 | 
				
			||||||
 | 
					                <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>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        -->
 | 
				
			||||||
 | 
					                <li style="border-left:none" id="categories"><a title="Browse Torrent Categories" href="/browse.html">Categories</a>
 | 
				
			||||||
 | 
					                    <ul>
 | 
				
			||||||
 | 
					                        <li><a title="Browse Anime Torrents" href="/browse.html#6">Anime</a></li>
 | 
				
			||||||
 | 
					                        <li><a title="Browse Game Torrents" href="/browse.html#4">Games</a></li>
 | 
				
			||||||
 | 
					                        <li><a title="Browse Movie Torrents" href="/browse.html#1">Movies</a></li>
 | 
				
			||||||
 | 
					                        <li><a title="Browse Music Torrents" href="/browse.html#3">Music</a></li>
 | 
				
			||||||
 | 
					                        <li><a title="Browse Software Torrents" href="/browse.html#5">Software</a></li>
 | 
				
			||||||
 | 
					                        <li><a title="Browse TV Torrents" href="/browse.html#2">TV Shows</a></li>
 | 
				
			||||||
 | 
					                        <li><a title="Browse Other Torrents" href="/browse.html#7">Others</a></li>
 | 
				
			||||||
 | 
					                    </ul>
 | 
				
			||||||
 | 
					                    </li>
 | 
				
			||||||
 | 
					                        <li><a title="Upload A Torrents" href="/upload.html">Upload torrent</a></li>
 | 
				
			||||||
 | 
					                        <li id="verified"><a title="Verified Torrents" href="/verified.html">Verified</a></li>
 | 
				
			||||||
 | 
					                        <li id="searchoptions"><a title="Search Torrents" href="/search.html">Torrent search</a></li>
 | 
				
			||||||
 | 
					                        <li id="newsgroups"><a style="color:#212b3e" title="News Groups" href="/usenet.html">Usenet Binaries</a></li>
 | 
				
			||||||
 | 
					                        <li id="about" style="border-right:none"><a rel="nofollow" href="/faq.html">About Us</a>
 | 
				
			||||||
 | 
					                    <ul>
 | 
				
			||||||
 | 
					                        <li><a title="SeedPeer Statistics" href="/stats.html">Statistics</a></li>
 | 
				
			||||||
 | 
					                        <li><a title="Contact Us" href="/contact.html">Contact</a></li>
 | 
				
			||||||
 | 
					                        <li><a title="Frequently  Asked Questions" href="/faq.html">FAQ</a></li>
 | 
				
			||||||
 | 
					                        <li><a title="SeedPeer API" href="http://api.seedpeer.eu">Our API</a></li>
 | 
				
			||||||
 | 
					                        <li><a title="SeedPeer Blog" href="/blog">Blog</a></li>
 | 
				
			||||||
 | 
					                    </ul>
 | 
				
			||||||
 | 
					                    </li>
 | 
				
			||||||
 | 
					                    <!--<li><a href="/toolbar.php">Our Toolbar</a></li>-->
 | 
				
			||||||
 | 
					                </ul>
 | 
				
			||||||
 | 
					            <div class="clear"></div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div id="body"><div id="pageTop"></div>
 | 
				
			||||||
 | 
					        <div id="headerbox"><h1>Verified <font class="colored">Narcos season 2</font> torrents</h1></div><table width="100%"><tr><th>
 | 
				
			||||||
 | 
					        <span style="float:right">
 | 
				
			||||||
 | 
					        <a href="/search/narcos-season-2/8/1.html"><img style="vertical-align:middle" src="/images/comments.gif" alt="comments" /></a> |
 | 
				
			||||||
 | 
					        <a href="/search/narcos-season-2/7/1.html"><img style="vertical-align:middle" src="/images/ver.gif" alt="verified" /></a>
 | 
				
			||||||
 | 
					        </span>
 | 
				
			||||||
 | 
					        <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> 2 <font class="colored">Narcos season 2</font> Torrents were found</h1></div><table width="100%"><tr><th>
 | 
				
			||||||
 | 
					        <span style="float:right">
 | 
				
			||||||
 | 
					        <a href="/search/narcos-season-2/8/1.html"><img style="vertical-align:middle" src="/images/comments.gif" alt="comments" /></a> |
 | 
				
			||||||
 | 
					        <a href="/search/narcos-season-2/7/1.html"><img style="vertical-align:middle" src="/images/ver.gif" alt="verified" /></a>
 | 
				
			||||||
 | 
					        </span>
 | 
				
			||||||
 | 
					        <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> <iframe src='http://creative.wwwpromoter.com/13689?d=300x250' width='300' height='250' style='border: none;' frameborder='0' scrolling='no'></iframe> <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">
 | 
				
			||||||
 | 
					        <table width="100%">
 | 
				
			||||||
 | 
					        <tr>
 | 
				
			||||||
 | 
					        <td width="30%">
 | 
				
			||||||
 | 
					        <h2>Torrents Download</h2>
 | 
				
			||||||
 | 
					        <a href="/">Torrent search</a><br />
 | 
				
			||||||
 | 
					        <a href="/browse.html">Browse categories</a><br />
 | 
				
			||||||
 | 
					        <a href="/verified.html">Verified Torrents</a><br />
 | 
				
			||||||
 | 
					        <a href="/order-date.html">Today's torrents</a><br />
 | 
				
			||||||
 | 
					        <a href="/yesterday.html">Yesterday's torrents</a><br />
 | 
				
			||||||
 | 
					        <a href="/stats.html">Statistics</a><br />
 | 
				
			||||||
 | 
					        <br />
 | 
				
			||||||
 | 
					        <a href="/faq.html#copyright"><strong>Copyright & Removal</strong></a>
 | 
				
			||||||
 | 
					        </td>
 | 
				
			||||||
 | 
					        <td width="30%"><h2>Cool Stuff</h2>
 | 
				
			||||||
 | 
					        <a href="/promotional.php">Promotional</a><br />
 | 
				
			||||||
 | 
					        <a href="/contact.html">Advertising Information</a><br />
 | 
				
			||||||
 | 
					        <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 />
 | 
				
			||||||
 | 
					        <a href="http://www.utorrent.com">µTorrent Client</a><br />
 | 
				
			||||||
 | 
					        <a href="/blog">Seedpeer Blog</a><br />
 | 
				
			||||||
 | 
					        </td>
 | 
				
			||||||
 | 
					        <td width="30%"><h2>Links</h2>
 | 
				
			||||||
 | 
					         <a href="http://www.sumotorrent.com" target="_blank"><strong>SumoTorrent</strong></a><br />
 | 
				
			||||||
 | 
					         <a href="http://www.torrent-finder.info" target="_blank"><strong>Torrent Finder</strong></a><br />
 | 
				
			||||||
 | 
					         <a href="http://www.torrentpond.com" target="_blank"><strong>TorrentPond</strong></a><br />
 | 
				
			||||||
 | 
					         <a href="https://www.limetorrents.cc" target="_blank">LimeTorrents.cc</a><br />
 | 
				
			||||||
 | 
					         <a href="http://www.torrents.to/" target="_blank">Torrents.to</a><br />
 | 
				
			||||||
 | 
					         <a href="http://www.torrentfunk.com" target="_blank">TorrentFunk</a><br />
 | 
				
			||||||
 | 
					         <a href="https://monova.org" target="_blank">Monova</a><br />
 | 
				
			||||||
 | 
					         <a href="http://www.torrentroom.com" target="_blank">TorrentRoom</a><br />
 | 
				
			||||||
 | 
					         <a href="http://www.katcr.co/" target="_blank">Kickass Torrents Community</a><br />
 | 
				
			||||||
 | 
					        </td>
 | 
				
			||||||
 | 
					        <td width="10%"><div id="bottomlogo"></div></td>
 | 
				
			||||||
 | 
					        </tr>
 | 
				
			||||||
 | 
					        </table>
 | 
				
			||||||
 | 
					        <br />
 | 
				
			||||||
 | 
					        <br />
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        </body>
 | 
				
			||||||
 | 
					        </html>
 | 
				
			||||||
| 
						 | 
					@ -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">
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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 years</td>
 | 
					                <td class="center">2 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 > Unsorted')
 | 
					        self.assertEqual(results[0]['content'], 'Posted by riri in Other > 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 years</td>
 | 
					                <td class="center">2 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 years</td>
 | 
					                <td class="center">2 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 years</td>
 | 
					                <td class="center">2 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 years</td>
 | 
					                <td class="center">2 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 years</td>
 | 
					                <td class="center">2 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 > Unsorted')
 | 
					        self.assertEqual(results[0]['content'], 'Posted by riri in Other > 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[0]['filesize'], 1000)
 | 
				
			||||||
        self.assertEqual(results[1]['filesize'], 1048576)
 | 
					        self.assertEqual(results[1]['filesize'], 1000000)
 | 
				
			||||||
        self.assertEqual(results[2]['filesize'], 1073741824)
 | 
					        self.assertEqual(results[2]['filesize'], 1000000000)
 | 
				
			||||||
        self.assertEqual(results[3]['filesize'], 1099511627776)
 | 
					        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
									
								
								tests/unit/engines/test_pdbe.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -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 (OBSOLETE)')
 | 
				
			||||||
 | 
					        self.assertTrue(results[0]['content'].startswith('<em>This entry has been superseded by'))
 | 
				
			||||||
							
								
								
									
										51
									
								
								tests/unit/engines/test_seedpeer.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -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')
 | 
				
			||||||
| 
						 | 
					@ -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(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||