update searx 0.7

This commit is contained in:
root 2015-02-09 13:30:16 +01:00
parent 6ecbcec92e
commit 0fa40c6d96
162 changed files with 6509 additions and 2157 deletions

View File

@ -6,6 +6,7 @@ Major contributing authors:
- Matej Cotman
- Thomas Pointhuber
- Alexandre Flament
- @Cqoicebordel
People who have submitted patches/translates, reported bugs, consulted features or
generally made searx better:
@ -27,8 +28,8 @@ generally made searx better:
- Martin Zimmermann
- @courgette
- @kernc
- @Cqoicebordel
- @Reventl0v
- Caner Başaran
- Benjamin Sonntag
- @opi
- @dimqua

View File

@ -1,3 +1,35 @@
0.7.0 2015.02.03
================
- New engines
- Digg
- Google Play Store
- Deezer
- Btdigg
- Mixcloud
- 1px
- Image proxy
- Search speed improvements
- Autocompletition of engines, shortcuts and supported languages
- Translation updates (New locales: Turkish, Russian)
- Default theme changed to oscar
- Settings option to disable engines by default
- UI code cleanup and restructure
- Engine tests
- Multiple engine bug fixes and tweaks
- Config option to set default interface locale
- Flexible result template handling
- Application logging and sophisticated engine exception tracebacks
- Kickass torrent size display (oscar theme)
New dependencies
~~~~~~~~~~~~~~~~
- pygments - http://pygments.org/
0.6.0 - 2014.12.25
==================

View File

@ -46,6 +46,7 @@ minimal: bin/buildout minimal.cfg setup.py
styles:
@lessc -x searx/static/themes/default/less/style.less > searx/static/themes/default/css/style.css
@lessc -x searx/static/themes/courgette/less/style.less > searx/static/themes/courgette/css/style.css
@lessc -x searx/static/less/bootstrap/bootstrap.less > searx/static/css/bootstrap.min.css
@lessc -x searx/static/themes/oscar/less/oscar/oscar.less > searx/static/themes/oscar/css/oscar.min.css

View File

@ -3,4 +3,5 @@ flask-babel
requests
lxml
pyyaml
pygments
python-dateutil

View File

@ -17,13 +17,13 @@ along with searx. If not, see < http://www.gnu.org/licenses/ >.
from lxml import etree
from requests import get
from json import loads
from urllib import urlencode
from searx.languages import language_codes
from searx.engines import (
categories, engines, engine_shortcuts
)
from searx.poolrequests import get
def searx_bang(full_query):
@ -35,33 +35,34 @@ def searx_bang(full_query):
results = []
# check if current query stats with !bang
if full_query.getSearchQuery()[0] == '!':
first_char = full_query.getSearchQuery()[0]
if first_char == '!' or first_char == '?':
if len(full_query.getSearchQuery()) == 1:
# show some example queries
# TODO, check if engine is not avaliable
results.append("!images")
results.append("!wikipedia")
results.append("!osm")
results.append(first_char + "images")
results.append(first_char + "wikipedia")
results.append(first_char + "osm")
else:
engine_query = full_query.getSearchQuery()[1:]
# check if query starts with categorie name
for categorie in categories:
if categorie.startswith(engine_query):
results.append('!{categorie}'.format(categorie=categorie))
results.append(first_char+'{categorie}'.format(categorie=categorie))
# check if query starts with engine name
for engine in engines:
if engine.startswith(engine_query.replace('_', ' ')):
results.append('!{engine}'.format(engine=engine.replace(' ', '_')))
results.append(first_char+'{engine}'.format(engine=engine.replace(' ', '_')))
# check if query starts with engine shortcut
for engine_shortcut in engine_shortcuts:
if engine_shortcut.startswith(engine_query):
results.append('!{engine_shortcut}'.format(engine_shortcut=engine_shortcut))
results.append(first_char+'{engine_shortcut}'.format(engine_shortcut=engine_shortcut))
# check if current query stats with :bang
elif full_query.getSearchQuery()[0] == ':':
elif first_char == ':':
if len(full_query.getSearchQuery()) == 1:
# show some example queries
results.append(":en")

View File

@ -69,17 +69,17 @@ def load_engine(engine_data):
engine.categories = ['general']
if not hasattr(engine, 'language_support'):
# engine.language_support = False
engine.language_support = True
if not hasattr(engine, 'timeout'):
# engine.language_support = False
engine.timeout = settings['server']['request_timeout']
if not hasattr(engine, 'shortcut'):
# engine.shortcut = '''
engine.shortcut = ''
if not hasattr(engine, 'disabled'):
engine.disabled = False
# checking required variables
for engine_attr in dir(engine):
if engine_attr.startswith('_'):

View File

@ -14,6 +14,7 @@
from urllib import urlencode
from cgi import escape
from lxml import html
from searx.engines.xpath import extract_text
# engine dependent config
categories = ['general']
@ -55,8 +56,8 @@ def response(resp):
for result in dom.xpath('//div[@class="sa_cc"]'):
link = result.xpath('.//h3/a')[0]
url = link.attrib.get('href')
title = ' '.join(link.xpath('.//text()'))
content = escape(' '.join(result.xpath('.//p//text()')))
title = extract_text(link)
content = escape(extract_text(result.xpath('.//p')))
# append result
results.append({'url': url,
@ -71,8 +72,8 @@ def response(resp):
for result in dom.xpath('//li[@class="b_algo"]'):
link = result.xpath('.//h2/a')[0]
url = link.attrib.get('href')
title = ' '.join(link.xpath('.//text()'))
content = escape(' '.join(result.xpath('.//p//text()')))
title = extract_text(link)
content = escape(extract_text(result.xpath('.//p')))
# append result
results.append({'url': url,

View File

@ -25,6 +25,7 @@ paging = True
# search-url
base_url = 'https://www.bing.com/'
search_string = 'images/search?{query}&count=10&first={offset}'
thumb_url = "http://ts1.mm.bing.net/th?id={ihk}"
# do search-request
@ -32,7 +33,10 @@ def request(query, params):
offset = (params['pageno'] - 1) * 10 + 1
# required for cookie
language = 'en-US'
if params['language'] == 'all':
language = 'en-US'
else:
language = params['language'].replace('_', '-')
search_path = search_string.format(
query=urlencode({'q': query}),
@ -63,6 +67,8 @@ def response(resp):
yaml_data = load(p.sub(r'\1\2: \3', link.attrib.get('m')))
title = link.attrib.get('t1')
ihk = link.attrib.get('ihk')
#url = 'http://' + link.attrib.get('t3')
url = yaml_data.get('surl')
img_src = yaml_data.get('imgurl')
@ -72,6 +78,7 @@ def response(resp):
'url': url,
'title': title,
'content': '',
'thumbnail_src': thumb_url.format(ihk=ihk),
'img_src': img_src})
# TODO stop parsing if 10 images are found

View File

@ -15,6 +15,7 @@ from lxml import html
from datetime import datetime, timedelta
from dateutil import parser
import re
from searx.engines.xpath import extract_text
# engine dependent config
categories = ['news']
@ -39,10 +40,10 @@ def request(query, params):
query=urlencode({'q': query, 'setmkt': language}),
offset=offset)
params['cookies']['SRCHHPGUSR'] = \
'NEWWND=0&NRSLT=-1&SRCHLANG=' + language.split('-')[0]
params['cookies']['_FP'] = "ui=en-US"
params['url'] = base_url + search_path
return params
@ -56,44 +57,35 @@ def response(resp):
for result in dom.xpath('//div[@class="sn_r"]'):
link = result.xpath('.//div[@class="newstitle"]/a')[0]
url = link.attrib.get('href')
title = ' '.join(link.xpath('.//text()'))
contentXPath = result.xpath('.//div[@class="sn_txt"]/div'
'//span[@class="sn_snip"]//text()')
if contentXPath is not None:
content = escape(' '.join(contentXPath))
title = extract_text(link)
contentXPath = result.xpath('.//div[@class="sn_txt"]/div//span[@class="sn_snip"]')
content = escape(extract_text(contentXPath))
# parse publishedDate
publishedDateXPath = result.xpath('.//div[@class="sn_txt"]/div'
'//span[contains(@class,"sn_ST")]'
'//span[contains(@class,"sn_tm")]'
'//text()')
if publishedDateXPath is not None:
publishedDate = escape(' '.join(publishedDateXPath))
'//span[contains(@class,"sn_tm")]')
publishedDate = escape(extract_text(publishedDateXPath))
if re.match("^[0-9]+ minute(s|) ago$", publishedDate):
timeNumbers = re.findall(r'\d+', publishedDate)
publishedDate = datetime.now()\
- timedelta(minutes=int(timeNumbers[0]))
publishedDate = datetime.now() - timedelta(minutes=int(timeNumbers[0]))
elif re.match("^[0-9]+ hour(s|) ago$", publishedDate):
timeNumbers = re.findall(r'\d+', publishedDate)
publishedDate = datetime.now()\
- timedelta(hours=int(timeNumbers[0]))
elif re.match("^[0-9]+ hour(s|),"
" [0-9]+ minute(s|) ago$", publishedDate):
publishedDate = datetime.now() - timedelta(hours=int(timeNumbers[0]))
elif re.match("^[0-9]+ hour(s|), [0-9]+ minute(s|) ago$", publishedDate):
timeNumbers = re.findall(r'\d+', publishedDate)
publishedDate = datetime.now()\
- timedelta(hours=int(timeNumbers[0]))\
- timedelta(minutes=int(timeNumbers[1]))
elif re.match("^[0-9]+ day(s|) ago$", publishedDate):
timeNumbers = re.findall(r'\d+', publishedDate)
publishedDate = datetime.now()\
- timedelta(days=int(timeNumbers[0]))
publishedDate = datetime.now() - timedelta(days=int(timeNumbers[0]))
else:
try:
# FIXME use params['language'] to parse either mm/dd or dd/mm
publishedDate = parser.parse(publishedDate, dayfirst=False)
except TypeError:
# FIXME
publishedDate = datetime.now()
# append result

View File

@ -0,0 +1,104 @@
## BTDigg (Videos, Music, Files)
#
# @website https://btdigg.org
# @provide-api yes (on demand)
#
# @using-api no
# @results HTML (using search portal)
# @stable no (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
# engine dependent config
categories = ['videos', 'music', 'files']
paging = True
# search-url
url = 'https://btdigg.org'
search_url = url + '/search?q={search_term}&p={pageno}'
# do search-request
def request(query, params):
params['url'] = search_url.format(search_term=quote(query),
pageno=params['pageno']-1)
return params
# get response from search-request
def response(resp):
results = []
dom = html.fromstring(resp.text)
search_res = dom.xpath('//div[@id="search_res"]/table/tr')
# return empty array if nothing is found
if not search_res:
return []
# parse results
for result in search_res:
link = result.xpath('.//td[@class="torrent_name"]//a')[0]
href = urljoin(url, link.attrib.get('href'))
title = escape(extract_text(link))
content = escape(extract_text(result.xpath('.//pre[@class="snippet"]')[0]))
content = "<br />".join(content.split("\n"))
filesize = result.xpath('.//span[@class="attr_val"]/text()')[0].split()[0]
filesize_multiplier = result.xpath('.//span[@class="attr_val"]/text()')[0].split()[1]
files = result.xpath('.//span[@class="attr_val"]/text()')[1]
seed = result.xpath('.//span[@class="attr_val"]/text()')[2]
# convert seed to int if possible
if seed.isdigit():
seed = int(seed)
else:
seed = 0
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():
files = int(files)
else:
files = None
magnetlink = result.xpath('.//td[@class="ttth"]//a')[0].attrib['href']
# append result
results.append({'url': href,
'title': title,
'content': content,
'seed': seed,
'leech': leech,
'filesize': filesize,
'files': files,
'magnetlink': magnetlink,
'template': 'torrent.html'})
# return results sorted by seeder
return sorted(results, key=itemgetter('seed'), reverse=True)

View File

@ -6,13 +6,15 @@
# @using-api no (TODO, rewrite to api)
# @results HTML
# @stable no (HTML can change)
# @parse url, title, thumbnail, img_src
# @parse url, title, thumbnail_src, img_src
#
# @todo rewrite to api
from urllib import urlencode
from urlparse import urljoin
from lxml import html
import re
from searx.engines.xpath import extract_text
# engine dependent config
categories = ['images']
@ -43,18 +45,22 @@ def response(resp):
dom = html.fromstring(resp.text)
regex = re.compile('\/200H\/')
# parse results
for result in dom.xpath('//div[contains(@class, "tt-a tt-fh")]'):
link = result.xpath('.//a[contains(@class, "thumb")]')[0]
url = urljoin(base_url, link.attrib.get('href'))
title_links = result.xpath('.//span[@class="details"]//a[contains(@class, "t")]') # noqa
title = ''.join(title_links[0].xpath('.//text()'))
img_src = link.xpath('.//img')[0].attrib['src']
title_links = result.xpath('.//span[@class="details"]//a[contains(@class, "t")]')
title = extract_text(title_links[0])
thumbnail_src = link.xpath('.//img')[0].attrib.get('src')
img_src = regex.sub('/', thumbnail_src)
# append result
results.append({'url': url,
'title': title,
'img_src': img_src,
'thumbnail_src': thumbnail_src,
'template': 'images.html'})
# return results

View File

@ -44,7 +44,7 @@ def response(resp):
search_result = loads(resp.text)
if search_result['html'] == '':
if 'html' not in search_result or search_result['html'] == '':
return results
dom = html.fromstring(search_result['html'])

View File

@ -23,7 +23,7 @@ api_key = None
url = 'https://api.flickr.com/services/rest/?method=flickr.photos.search' +\
'&api_key={api_key}&{text}&sort=relevance' +\
'&extras=description%2C+owner_name%2C+url_o%2C+url_z' +\
'&extras=description%2C+owner_name%2C+url_o%2C+url_n%2C+url_z' +\
'&per_page={nb_per_page}&format=json&nojsoncallback=1&page={page}'
photo_url = 'https://www.flickr.com/photos/{userid}/{photoid}'
@ -65,6 +65,14 @@ def response(resp):
else:
continue
# For a bigger thumbnail, keep only the url_z, not the url_n
if 'url_n' in photo:
thumbnail_src = photo['url_n']
elif 'url_z' in photo:
thumbnail_src = photo['url_z']
else:
thumbnail_src = img_src
url = build_flickr_url(photo['owner'], photo['id'])
title = photo['title']
@ -80,6 +88,7 @@ def response(resp):
results.append({'url': url,
'title': title,
'img_src': img_src,
'thumbnail_src': thumbnail_src,
'content': content,
'template': 'images.html'})

View File

@ -0,0 +1,109 @@
#!/usr/bin/env python
# Flickr (Images)
#
# @website https://www.flickr.com
# @provide-api yes (https://secure.flickr.com/services/api/flickr.photos.search.html)
#
# @using-api no
# @results HTML
# @stable no
# @parse url, title, thumbnail, img_src
from urllib import urlencode
from json import loads
import re
from searx.engines import logger
logger = logger.getChild('flickr-noapi')
categories = ['images']
url = 'https://secure.flickr.com/'
search_url = url + 'search/?{query}&page={page}'
photo_url = 'https://www.flickr.com/photos/{userid}/{photoid}'
regex = re.compile(r"\"search-photos-models\",\"photos\":(.*}),\"totalItems\":", re.DOTALL)
image_sizes = ('o', 'k', 'h', 'b', 'c', 'z', 'n', 'm', 't', 'q', 's')
paging = True
def build_flickr_url(user_id, photo_id):
return photo_url.format(userid=user_id, photoid=photo_id)
def request(query, params):
params['url'] = search_url.format(query=urlencode({'text': query}),
page=params['pageno'])
return params
def response(resp):
results = []
matches = regex.search(resp.text)
if matches is None:
return results
match = matches.group(1)
search_results = loads(match)
if '_data' not in search_results:
return []
photos = search_results['_data']
for photo in photos:
# In paged configuration, the first pages' photos
# are represented by a None object
if photo is None:
continue
img_src = None
# From the biggest to the lowest format
for image_size in image_sizes:
if image_size in photo['sizes']:
img_src = photo['sizes'][image_size]['url']
break
if not img_src:
logger.debug('cannot find valid image size: {0}'.format(repr(photo)))
continue
if 'id' not in photo['owner']:
continue
# For a bigger thumbnail, keep only the url_z, not the url_n
if 'n' in photo['sizes']:
thumbnail_src = photo['sizes']['n']['url']
elif 'z' in photo['sizes']:
thumbnail_src = photo['sizes']['z']['url']
else:
thumbnail_src = img_src
url = build_flickr_url(photo['owner']['id'], photo['id'])
title = photo.get('title', '')
content = '<span class="photo-author">' +\
photo['owner']['username'] +\
'</span><br />'
if 'description' in photo:
content = content +\
'<span class="description">' +\
photo['description'] +\
'</span>'
# append result
results.append({'url': url,
'title': title,
'img_src': img_src,
'thumbnail_src': thumbnail_src,
'content': content,
'template': 'images.html'})
return results

View File

@ -11,6 +11,7 @@
from urllib import urlencode
from urlparse import urlparse, parse_qsl
from lxml import html
from searx.poolrequests import get
from searx.engines.xpath import extract_text, extract_url
# engine dependent config
@ -39,6 +40,17 @@ images_xpath = './/div/a'
image_url_xpath = './@href'
image_img_src_xpath = './img/@src'
pref_cookie = ''
# see https://support.google.com/websearch/answer/873?hl=en
def get_google_pref_cookie():
global pref_cookie
if pref_cookie == '':
resp = get('https://www.google.com/ncr', allow_redirects=False)
pref_cookie = resp.cookies["PREF"]
return pref_cookie
# remove google-specific tracking-url
def parse_url(url_string):
@ -64,6 +76,7 @@ def request(query, params):
query=urlencode({'q': query}))
params['headers']['Accept-Language'] = language
params['cookies']['PREF'] = get_google_pref_cookie()
return params

View File

@ -18,7 +18,7 @@ paging = True
# search-url
url = 'https://ajax.googleapis.com/'
search_url = url + 'ajax/services/search/images?v=1.0&start={offset}&rsz=large&safe=off&filter=off&{query}' # noqa
search_url = url + 'ajax/services/search/images?v=1.0&start={offset}&rsz=large&safe=off&filter=off&{query}'
# do search-request
@ -45,13 +45,15 @@ def response(resp):
for result in search_res['responseData']['results']:
href = result['originalContextUrl']
title = result['title']
if not result['url']:
if 'url' not in result:
continue
thumbnail_src = result['tbUrl']
# append result
results.append({'url': href,
'title': title,
'content': '',
'content': result['content'],
'thumbnail_src': thumbnail_src,
'img_src': unquote(result['url']),
'template': 'images.html'})

View File

@ -20,7 +20,7 @@ language_support = True
# engine dependent config
url = 'https://ajax.googleapis.com/'
search_url = url + 'ajax/services/search/news?v=2.0&start={offset}&rsz=large&safe=off&filter=off&{query}&hl={language}' # noqa
search_url = url + 'ajax/services/search/news?v=2.0&start={offset}&rsz=large&safe=off&filter=off&{query}&hl={lang}'
# do search-request
@ -33,7 +33,7 @@ def request(query, params):
params['url'] = search_url.format(offset=offset,
query=urlencode({'q': query}),
language=language)
lang=language)
return params
@ -52,6 +52,8 @@ def response(resp):
for result in search_res['responseData']['results']:
# parse publishedDate
publishedDate = parser.parse(result['publishedDate'])
if 'url' not in result:
continue
# append result
results.append({'url': result['unescapedUrl'],

View File

@ -13,6 +13,7 @@ from cgi import escape
from urllib import quote
from lxml import html
from operator import itemgetter
from searx.engines.xpath import extract_text
# engine dependent config
categories = ['videos', 'music', 'files']
@ -56,9 +57,8 @@ def response(resp):
for result in search_res[1:]:
link = result.xpath('.//a[@class="cellMainLink"]')[0]
href = urljoin(url, link.attrib['href'])
title = ' '.join(link.xpath('.//text()'))
content = escape(html.tostring(result.xpath(content_xpath)[0],
method="text"))
title = extract_text(link)
content = escape(extract_text(result.xpath(content_xpath)))
seed = result.xpath('.//td[contains(@class, "green")]/text()')[0]
leech = result.xpath('.//td[contains(@class, "red")]/text()')[0]
filesize = result.xpath('.//td[contains(@class, "nobr")]/text()')[0]
@ -88,7 +88,7 @@ def response(resp):
filesize = int(filesize * 1024 * 1024 * 1024)
elif filesize_multiplier == 'MB':
filesize = int(filesize * 1024 * 1024)
elif filesize_multiplier == 'kb':
elif filesize_multiplier == 'KB':
filesize = int(filesize * 1024)
except:
filesize = None

View File

@ -0,0 +1,59 @@
## Mixcloud (Music)
#
# @website https://http://www.mixcloud.com/
# @provide-api yes (http://www.mixcloud.com/developers/
#
# @using-api yes
# @results JSON
# @stable yes
# @parse url, title, content, embedded, publishedDate
from json import loads
from urllib import urlencode
from dateutil import parser
# engine dependent config
categories = ['music']
paging = True
# search-url
url = 'http://api.mixcloud.com/'
search_url = url + 'search/?{query}&type=cloudcast&limit=10&offset={offset}'
embedded_url = '<iframe scrolling="no" frameborder="0" allowTransparency="true" ' +\
'data-src="https://www.mixcloud.com/widget/iframe/?feed={url}" width="300" height="300"></iframe>'
# do search-request
def request(query, params):
offset = (params['pageno'] - 1) * 10
params['url'] = search_url.format(query=urlencode({'q': query}),
offset=offset)
return params
# get response from search-request
def response(resp):
results = []
search_res = loads(resp.text)
# parse results
for result in search_res.get('data', []):
title = result['name']
url = result['url']
content = result['user']['name']
embedded = embedded_url.format(url=url)
publishedDate = parser.parse(result['created_time'])
# append result
results.append({'url': url,
'title': title,
'embedded': embedded,
'publishedDate': publishedDate,
'content': content})
# return results
return results

View File

@ -13,13 +13,14 @@ from cgi import escape
from urllib import quote
from lxml import html
from operator import itemgetter
from searx.engines.xpath import extract_text
# engine dependent config
categories = ['videos', 'music', 'files']
paging = True
# search-url
url = 'https://thepiratebay.cr/'
url = 'https://thepiratebay.se/'
search_url = url + 'search/{search_term}/{pageno}/99/{search_type}'
# piratebay specific type-definitions
@ -29,7 +30,8 @@ search_types = {'files': '0',
# specific xpath variables
magnet_xpath = './/a[@title="Download this torrent using magnet"]'
content_xpath = './/font[@class="detDesc"]//text()'
torrent_xpath = './/a[@title="Download this torrent"]'
content_xpath = './/font[@class="detDesc"]'
# do search-request
@ -59,8 +61,8 @@ def response(resp):
for result in search_res[1:]:
link = result.xpath('.//div[@class="detName"]//a')[0]
href = urljoin(url, link.attrib.get('href'))
title = ' '.join(link.xpath('.//text()'))
content = escape(' '.join(result.xpath(content_xpath)))
title = extract_text(link)
content = escape(extract_text(result.xpath(content_xpath)))
seed, leech = result.xpath('.//td[@align="right"]/text()')[:2]
# convert seed to int if possible
@ -76,6 +78,7 @@ def response(resp):
leech = 0
magnetlink = result.xpath(magnet_xpath)[0]
torrentfile = result.xpath(torrent_xpath)[0]
# append result
results.append({'url': href,
@ -83,7 +86,8 @@ def response(resp):
'content': content,
'seed': seed,
'leech': leech,
'magnetlink': magnetlink.attrib['href'],
'magnetlink': magnetlink.attrib.get('href'),
'torrentfile': torrentfile.attrib.get('href'),
'template': 'torrent.html'})
# return results sorted by seeder

View File

@ -10,7 +10,7 @@
from urllib import urlencode
from json import loads
import cgi
# engine dependent config
categories = ['it']
@ -20,6 +20,12 @@ paging = True
url = 'https://searchcode.com/'
search_url = url+'api/codesearch_I/?{query}&p={pageno}'
# special code-endings which are not recognised by the file ending
code_endings = {'cs': 'c#',
'h': 'c',
'hpp': 'cpp',
'cxx': 'cpp'}
# do search-request
def request(query, params):
@ -36,30 +42,27 @@ def response(resp):
search_results = loads(resp.text)
# parse results
for result in search_results['results']:
for result in search_results.get('results', []):
href = result['url']
title = "" + result['name'] + " - " + result['filename']
content = result['repo'] + "<br />"
repo = result['repo']
lines = dict()
for line, code in result['lines'].items():
lines[int(line)] = code
content = content + '<pre class="code-formatter"><table class="code">'
for line, code in sorted(lines.items()):
content = content + '<tr><td class="line-number" style="padding-right:5px;">'
content = content + str(line) + '</td><td class="code-snippet">'
# Replace every two spaces with ' &nbps;' to keep formatting
# while allowing the browser to break the line if necessary
content = content + cgi.escape(code).replace('\t', ' ').replace(' ', '&nbsp; ').replace(' ', ' &nbsp;')
content = content + "</td></tr>"
content = content + "</table></pre>"
code_language = code_endings.get(
result['filename'].split('.')[-1].lower(),
result['filename'].split('.')[-1].lower())
# append result
results.append({'url': href,
'title': title,
'content': content})
'content': '',
'repository': repo,
'codelines': sorted(lines.items()),
'code_language': code_language,
'template': 'code.html'})
# return results
return results

View File

@ -35,7 +35,7 @@ def response(resp):
search_results = loads(resp.text)
# parse results
for result in search_results['results']:
for result in search_results.get('results', []):
href = result['url']
title = "[" + result['type'] + "] " +\
result['namespace'] +\

View File

@ -12,6 +12,7 @@ from urlparse import urljoin
from cgi import escape
from urllib import urlencode
from lxml import html
from searx.engines.xpath import extract_text
# engine dependent config
categories = ['it']
@ -24,8 +25,7 @@ search_url = url+'search?{query}&page={pageno}'
# specific xpath variables
results_xpath = '//div[contains(@class,"question-summary")]'
link_xpath = './/div[@class="result-link"]//a|.//div[@class="summary"]//h3//a'
title_xpath = './/text()'
content_xpath = './/div[@class="excerpt"]//text()'
content_xpath = './/div[@class="excerpt"]'
# do search-request
@ -46,8 +46,8 @@ def response(resp):
for result in dom.xpath(results_xpath):
link = result.xpath(link_xpath)[0]
href = urljoin(url, link.attrib.get('href'))
title = escape(' '.join(link.xpath(title_xpath)))
content = escape(' '.join(result.xpath(content_xpath)))
title = escape(extract_text(link))
content = escape(extract_text(result.xpath(content_xpath)))
# append result
results.append({'url': href,

View File

@ -10,7 +10,6 @@
#
# @todo paging
from urllib import urlencode
from lxml import html
from cgi import escape
import re
@ -38,7 +37,6 @@ link_xpath = './/h3/a'
# do search-request
def request(query, params):
offset = (params['pageno'] - 1) * 10
query = urlencode({'q': query})[2:]
params['url'] = search_url
params['method'] = 'POST'

View File

@ -59,8 +59,7 @@ def response(resp):
url = base_url + videoid
title = p.unescape(extract_text(result.xpath(title_xpath)))
thumbnail = extract_text(result.xpath(content_xpath)[0])
publishedDate = parser.parse(extract_text(
result.xpath(publishedDate_xpath)[0]))
publishedDate = parser.parse(extract_text(result.xpath(publishedDate_xpath)[0]))
embedded = embedded_url.format(videoid=videoid)
# append result

View File

@ -1,6 +1,6 @@
import json
from requests import get
from urllib import urlencode
from searx.poolrequests import get
from searx.utils import format_date_by_locale
result_count = 1

View File

@ -0,0 +1,82 @@
## 1x (Images)
#
# @website http://1x.com/
# @provide-api no
#
# @using-api no
# @results HTML
# @stable no (HTML can change)
# @parse url, title, thumbnail, img_src, content
from urllib import urlencode
from urlparse import urljoin
from lxml import html
import string
import re
# engine dependent config
categories = ['images']
paging = False
# search-url
base_url = 'http://1x.com'
search_url = base_url+'/backend/search.php?{query}'
# do search-request
def request(query, params):
params['url'] = search_url.format(query=urlencode({'q': query}))
return params
# get response from search-request
def response(resp):
results = []
# get links from result-text
regex = re.compile('(</a>|<a)')
results_parts = re.split(regex, resp.text)
cur_element = ''
# iterate over link parts
for result_part in results_parts:
# processed start and end of link
if result_part == '<a':
cur_element = result_part
continue
elif result_part != '</a>':
cur_element += result_part
continue
cur_element += result_part
# fix xml-error
cur_element = string.replace(cur_element, '"></a>', '"/></a>')
dom = html.fromstring(cur_element)
link = dom.xpath('//a')[0]
url = urljoin(base_url, link.attrib.get('href'))
title = link.attrib.get('title', '')
thumbnail_src = urljoin(base_url, link.xpath('.//img')[0].attrib['src'])
# TODO: get image with higher resolution
img_src = thumbnail_src
# check if url is showing to a photo
if '/photo/' not in url:
continue
# append result
results.append({'url': url,
'title': title,
'img_src': img_src,
'content': '',
'thumbnail_src': thumbnail_src,
'template': 'images.html'})
# return results
return results

View File

@ -0,0 +1,64 @@
## 500px (Images)
#
# @website https://500px.com
# @provide-api yes (https://developers.500px.com/)
#
# @using-api no
# @results HTML
# @stable no (HTML can change)
# @parse url, title, thumbnail, img_src, content
#
# @todo rewrite to api
from urllib import urlencode
from urlparse import urljoin
from lxml import html
import re
from searx.engines.xpath import extract_text
# engine dependent config
categories = ['images']
paging = True
# search-url
base_url = 'https://500px.com'
search_url = base_url + '/search?search?page={pageno}&type=photos&{query}'
# do search-request
def request(query, params):
params['url'] = search_url.format(pageno=params['pageno'],
query=urlencode({'q': query}))
return params
# get response from search-request
def response(resp):
results = []
dom = html.fromstring(resp.text)
regex = re.compile('3\.jpg.*$')
# parse results
for result in dom.xpath('//div[@class="photo"]'):
link = result.xpath('.//a')[0]
url = urljoin(base_url, link.attrib.get('href'))
title = extract_text(result.xpath('.//div[@class="title"]'))
thumbnail_src = link.xpath('.//img')[0].attrib.get('src')
# To have a bigger thumbnail, uncomment the next line
# thumbnail_src = regex.sub('4.jpg', thumbnail_src)
content = extract_text(result.xpath('.//div[@class="info"]'))
img_src = regex.sub('2048.jpg', thumbnail_src)
# append result
results.append({'url': url,
'title': title,
'img_src': img_src,
'content': content,
'thumbnail_src': thumbnail_src,
'template': 'images.html'})
# return results
return results

View File

@ -28,13 +28,13 @@ def extract_text(xpath_results):
result = ''
for e in xpath_results:
result = result + extract_text(e)
return result
return result.strip()
elif type(xpath_results) in [_ElementStringResult, _ElementUnicodeResult]:
# it's a string
return ''.join(xpath_results)
else:
# it's a element
return html_to_text(xpath_results.text_content())
return html_to_text(xpath_results.text_content()).strip()
def extract_url(xpath_results, search_url):

View File

@ -68,9 +68,18 @@ def response(resp):
search_results = raw_search_results.get('channels', {})[0].get('items', [])
if resp.search_params['category'] == 'general':
for result in search_results:
# parse image results
if result.get('image'):
# append result
results.append({'url': result['url'],
'title': result['title'],
'content': '',
'img_src': result['image'],
'template': 'images.html'})
# parse general results
for result in search_results:
else:
publishedDate = parser.parse(result['pubDate'])
# append result
@ -79,17 +88,7 @@ def response(resp):
'content': result['description'],
'publishedDate': publishedDate})
elif resp.search_params['category'] == 'images':
# parse image results
for result in search_results:
# append result
results.append({'url': result['url'],
'title': result['title'],
'content': '',
'img_src': result['image'],
'template': 'images.html'})
#TODO parse video, audio and file results
#TODO parse video, audio and file results
# return results
return results

View File

@ -57,7 +57,7 @@ def response(resp):
url = [x['href'] for x in result['link'] if x['type'] == 'text/html']
if not url:
return
continue
# remove tracking
url = url[0].replace('feature=youtube_gdata', '')
@ -73,7 +73,7 @@ def response(resp):
pubdate = result['published']['$t']
publishedDate = parser.parse(pubdate)
if result['media$group']['media$thumbnail']:
if 'media$thumbnail' in result['media$group']:
thumbnail = result['media$group']['media$thumbnail'][0]['url']
content = result['content']['$t']

View File

@ -0,0 +1,61 @@
import requests
the_http_adapter = requests.adapters.HTTPAdapter(pool_connections=100)
the_https_adapter = requests.adapters.HTTPAdapter(pool_connections=100)
class SessionSinglePool(requests.Session):
def __init__(self):
global the_https_adapter, the_http_adapter
super(SessionSinglePool, self).__init__()
# reuse the same adapters
self.adapters.clear()
self.mount('https://', the_https_adapter)
self.mount('http://', the_http_adapter)
def close(self):
"""Call super, but clear adapters since there are managed globaly"""
self.adapters.clear()
super(SessionSinglePool, self).close()
def request(method, url, **kwargs):
"""same as requests/requests/api.py request(...) except it use SessionSinglePool"""
session = SessionSinglePool()
response = session.request(method=method, url=url, **kwargs)
session.close()
return response
def get(url, **kwargs):
kwargs.setdefault('allow_redirects', True)
return request('get', url, **kwargs)
def options(url, **kwargs):
kwargs.setdefault('allow_redirects', True)
return request('options', url, **kwargs)
def head(url, **kwargs):
kwargs.setdefault('allow_redirects', False)
return request('head', url, **kwargs)
def post(url, data=None, **kwargs):
return request('post', url, data=data, **kwargs)
def put(url, data=None, **kwargs):
return request('put', url, data=data, **kwargs)
def patch(url, data=None, **kwargs):
return request('patch', url, data=data, **kwargs)
def delete(url, **kwargs):
return request('delete', url, **kwargs)

View File

@ -88,18 +88,16 @@ class Query(object):
prefix = query_part[1:].replace('_', ' ')
# check if prefix is equal with engine shortcut
if prefix in engine_shortcuts\
and not engine_shortcuts[prefix] in self.blocked_engines:
if prefix in engine_shortcuts:
parse_next = True
self.engines.append({'category': 'none',
'name': engine_shortcuts[prefix]})
# check if prefix is equal with engine name
elif prefix in engines\
and prefix not in self.blocked_engines:
elif prefix in engines:
parse_next = True
self.engines.append({'category': 'none',
'name': prefix})
'name': prefix})
# check if prefix is equal with categorie name
elif prefix in categories:
@ -107,9 +105,9 @@ class Query(object):
# are declared under that categorie name
parse_next = True
self.engines.extend({'category': prefix,
'name': engine.name}
'name': engine.name}
for engine in categories[prefix]
if engine not in self.blocked_engines)
if (engine.name, prefix) not in self.blocked_engines)
if query_part[0] == '!':
self.specific = True

View File

@ -15,9 +15,9 @@ along with searx. If not, see < http://www.gnu.org/licenses/ >.
(C) 2013- by Adam Tauber, <asciimoo@gmail.com>
'''
import requests as requests_lib
import threading
import re
import searx.poolrequests as requests_lib
from itertools import izip_longest, chain
from operator import itemgetter
from Queue import Queue
@ -27,11 +27,10 @@ from searx.engines import (
categories, engines
)
from searx.languages import language_codes
from searx.utils import gen_useragent
from searx.utils import gen_useragent, get_blocked_engines
from searx.query import Query
from searx import logger
logger = logger.getChild('search')
number_of_searches = 0
@ -321,10 +320,7 @@ class Search(object):
self.lang = 'all'
# set blocked engines
if request.cookies.get('blocked_engines'):
self.blocked_engines = request.cookies['blocked_engines'].split(',') # noqa
else:
self.blocked_engines = []
self.blocked_engines = get_blocked_engines(engines, request.cookies)
self.results = []
self.suggestions = []
@ -384,12 +380,17 @@ class Search(object):
for pd_name, pd in self.request_data.items():
if pd_name.startswith('category_'):
category = pd_name[9:]
# if category is not found in list, skip
if category not in categories:
continue
# add category to list
self.categories.append(category)
if pd != 'off':
# add category to list
self.categories.append(category)
elif category in self.categories:
# remove category from list if property is set to 'off'
self.categories.remove(category)
# if no category is specified for this search,
# using user-defined default-configuration which
@ -410,9 +411,9 @@ class Search(object):
# declared under the specific categories
for categ in self.categories:
self.engines.extend({'category': categ,
'name': x.name}
for x in categories[categ]
if x.name not in self.blocked_engines)
'name': engine.name}
for engine in categories[categ]
if (engine.name, categ) not in self.blocked_engines)
# do search-request
def search(self, request):

View File

@ -4,10 +4,12 @@ server:
debug : False # Debug mode, only for development
request_timeout : 2.0 # seconds
base_url : False # Set custom base_url. Possible values: False or "https://your.custom.host/location/"
themes_path : "" # Custom ui themes path
default_theme : default # ui theme
themes_path : "" # Custom ui themes path - leave it blank if you didn't change
default_theme : oscar # ui theme
https_rewrite : True # Force rewrite result urls. See searx/https_rewrite.py
useragent_suffix : "" # suffix of searx_useragent, could contain informations like an email address to the administrator
image_proxy : False # Proxying image results through searx
default_locale : "" # Default interface locale - leave blank to detect from browser information or use codes from the 'locales' config section
engines:
- name : wikipedia
@ -31,11 +33,15 @@ engines:
locale : en-US
shortcut : bin
- name : btdigg
engine : btdigg
shortcut : bt
- name : currency
engine : currency_convert
categories : general
shortcut : cc
- name : deezer
engine : deezer
shortcut : dz
@ -48,7 +54,7 @@ engines:
- name : ddg definitions
engine : duckduckgo_definitions
shortcut : ddd
- name : digg
engine : digg
shortcut : dg
@ -72,11 +78,16 @@ engines:
# engine : filecrop
# categories : files
# shortcut : fc
- name : 500px
engine : 500px
engine : www500px
shortcut : px
- name : 1x
engine : www1x
shortcut : 1x
disabled : True
- name : flickr
categories : images
shortcut : fl
@ -85,11 +96,12 @@ engines:
# engine : flickr
# api_key: 'apikey' # required!
# Or you can use the html non-stable engine, activated by default
engine : flickr-noapi
engine : flickr_noapi
- name : general-file
engine : generalfile
shortcut : gf
disabled : True
- name : github
engine : github
@ -115,7 +127,8 @@ engines:
content_xpath : //a[@class="subtitle"]
categories : files
shortcut : gpa
disabled : True
- name : google play movies
engine : xpath
search_url : https://play.google.com/store/search?q={query}&c=movies
@ -124,7 +137,8 @@ engines:
content_xpath : //a[@class="subtitle"]
categories : videos
shortcut : gpm
disabled : True
- name : google play music
engine : xpath
search_url : https://play.google.com/store/search?q={query}&c=music
@ -133,7 +147,12 @@ engines:
content_xpath : //a[@class="subtitle"]
categories : music
shortcut : gps
disabled : True
- name : mixcloud
engine : mixcloud
shortcut : mc
- name : openstreetmap
engine : openstreetmap
shortcut : osm
@ -142,9 +161,9 @@ engines:
engine : photon
shortcut : ph
# - name : piratebay
# engine : piratebay
# shortcut : tpb
- name : piratebay
engine : piratebay
shortcut : tpb
- name : kickass
engine : kickass
@ -157,14 +176,15 @@ engines:
- name : stackoverflow
engine : stackoverflow
shortcut : st
- name : searchcode doc
engine : searchcode_doc
shortcut : scd
- name : searchcode code
engine : searchcode_code
shortcut : scc
disabled : True
- name : subtitleseeker
engine : subtitleseeker
@ -229,7 +249,7 @@ engines:
# shortcut : ya
# base_url : 'http://localhost:8090'
# number_of_results : 5
# timeout: 3.0
# timeout : 3.0
locales:
en : English
@ -241,3 +261,4 @@ locales:
nl : Nederlands
ja : 日本語 (Japanese)
tr : Türkçe
ru : Russian

View File

@ -7,6 +7,7 @@ server:
themes_path : ""
default_theme : default
https_rewrite : True
image_proxy : False
engines:
- name : general_dummy

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@ -0,0 +1,691 @@
@color-main: #3498DB;
@color-focus: #0665A2;
@color-other-links: #666;
@color-fonts: #333;
@center-width: 70em;
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
input[type="search"] {
-webkit-appearance: textfield;
}
h2 {
color: @color-other-links;
text-transform: uppercase;
}
body {
font-family: sans-serif;
line-height: 1.5;
margin: 0;
background: #EEE;
}
html {
position: relative;
min-height: 100%;
}
a {
color: @color-other-links;
}
.title h1 {
font-size:7em;
color:@color-main;
margin:0 auto;
line-height:100px;
margin-top:-20px;
padding-bottom:20px;
}
.center {
max-width: @center-width;
text-align: center;
background: rgba(255,255,255,0.6);
padding: 2em;
margin: 7% auto 0;
position: relative;
}
.center.search {
position: static;
width: auto;
background: none;
margin: auto;
padding-top: 1.8em;
}
@media screen and (min-width: 1001px) {
.center:after {
content: "";
z-index: -1;
background: url(../img/bg-body-index.jpg) no-repeat;
background-size: cover;
width: 100%;
height: 100%;
top: 0;
left: 0;
position: fixed;
}
.center.search:after {
content: none;
}
}
.autocompleter-choices {
position: absolute;
margin: 0;
padding: 0;
background: #FFF;
}
.autocompleter-choices li {
padding: 0.5em 1em;
}
.autocompleter-choices li:hover {
background: @color-main;
color: #FFF;
cursor: pointer;
}
#categories {
text-align: center;
}
.top_margin {
position: absolute;
bottom: -3.5em;
width: 100%;
left: 0;
}
.top_margin a {
display: inline-block;
margin-right: 1em;
color: #FFF;
text-decoration: none;
}
.top_margin a:hover,
.top_margin a:focus {
text-decoration: underline;
}
@media screen and (max-width: 1000px) {
.center { background: none; }
.top_margin a {
color: @color-fonts;
}
}
.checkbox_container { margin-top: 1.5em; }
.checkbox_container label {
padding: 0.5em 1em;
color: @color-fonts;
cursor: pointer;
font-size: 0.9em;
}
.checkbox_container label:hover {
background: @color-main;
color: #FFF;
}
.checkbox_container input[type="checkbox"] {
position: absolute;
top: -9999px;
}
.checkbox_container input[type="checkbox"]:checked + label {
background: @color-main;
color: #FFF;
}
#categories_container > div {
display: inline-block;
}
#categories .hidden {
display: none;
position: absolute;
bottom: 1em;
left: 0;
text-align: center;
width: 100%;
font-size: 0.9em;
font-style: italic;
color: @color-fonts;
}
#categories:hover .hidden {
display: block;
}
@media screen and (max-width: 900px) {
#categories_container { letter-spacing: -5px; }
#categories_container > div {
letter-spacing: normal;
margin-top: 1em;
}
.checkbox_container {
margin: 0;
}
.checkbox_container label {
display: block;
background: #CCC;
padding: 1em;
border: 1px solid #FFF;
}
.top_margin { position: static; }
#categories .hidden {
position: static;
display: block;
}
}
@media screen and (max-width: 900px) and (min-width: 501px) {
#categories_container > div {
width: 31%;
margin-left: 2.333%;
}
#categories_container > div:nth-child(3n+1) { margin-left: 0; }
}
@media screen and (max-width: 500px) {
#categories_container > div {
width: 48%;
margin-left: 2%;
font-size: 0.9em;
}
#categories_container > div:nth-child(2n+1) { margin-left: 0; }
.title h1 {
background: url(../img/searx-mobile.png) no-repeat;
width: 200px;
height: 39px;
}
}
#search_wrapper {
position: relative;
}
.q {
padding: 0.5em 3em 0.5em 1em;
width: 100%;
font-size: 1.5em;
border: 0;
color: #666;
}
#search_submit {
position: absolute;
top: 0;
right: 0;
border: 0;
background:url("../img/search-icon.png") no-repeat scroll center center / 65% auto @color-main;
text-indent: -9999px;
width: 5em;
height: 100%;
cursor: pointer;
}
#search_submit:hover,
#search_submit:focus {
background-color: @color-focus;
}
#sidebar {
background: @color-main;
position: fixed;
top: 0;
right: 0;
width: 15em;
height: 100%;
padding: 1.5em;
text-align: right;
}
.right {
position: fixed;
bottom: 1.5em;
width: 15em;
right: 0;
z-index: 1;
padding: 0 1.5em;
text-align: right;
}
.right a {
color: #FFF;
display: block;
text-decoration: none;
}
.right a:hover,
.right a:focus {
text-decoration: underline;
}
#preferences {
background: url(../img/preference-icon.png) no-repeat right 0 / 12% auto;
padding-right: 1.8em;
}
#preferences:hover,
#preferences:focus {
}
#search_url input {
border: 0;
padding: 0.5em;
}
#sidebar > div {
margin-bottom: 1em;
color: #FFF;
}
#sidebar form {
display: inline-block;
}
#sidebar input[type="submit"] {
background: #CCC;
border: 0;
padding: 0.5em 1em;
cursor: pointer;
margin-top: 0.5em;
}
#sidebar input[type="submit"]:hover,
#sidebar input[type="submit"]:focus {
color: #FFF;
background-color: @color-focus;
}
#results {
padding-right: 17em;
padding-left: 2em;
padding: 0 17em 0 2em;
}
.result p {
font-size: 0.9em;
}
.result .content {
margin: 0;
color: #666;
}
.result .url {
margin-top: 0;
color: #FF6530;
}
.result .favicon {
float: left;
position: relative;
top: 0.5em;
margin-right: 0.5em;
}
.definition_result {
background: #CCC;
padding: 1em;
}
.definition_result .result_title,
.definition_result p {
margin: 0;
}
.result_title {
margin-bottom: 0;
font-weight: normal;
}
.highlight {
font-weight: bold;
}
.result_title a {
color: @color-main;
text-decoration: none;
}
.result_title a:hover,
.result_title a:focus {
text-decoration: underline;
}
.cache_link {
color: #666;
font-size: 0.9em;
font-style: italic;
}
.search.center {
padding-right: 17em;
}
#answers {
border: 2px solid @color-main;
padding: 20px;
color:#666;
text-align: center;
max-width:@center-width;
margin:0 auto 20px;
}
#suggestions { margin-bottom: 1em; }
#suggestions span { color: #666; }
#suggestions form {
display: inline-block;
vertical-align: top;
margin-bottom: 0.5em;
}
#suggestions input[type="submit"] {
color: @color-fonts;
padding: 0.5em 1em;
border: 0;
background: #CCC;
cursor:pointer;
}
#suggestions input[type="submit"]:hover,
#suggestions input[type="submit"]:focus {
background: @color-main;
color: #FFF;
}
#pagination {
margin: 1.5em 0 2em;
}
#pagination form + form {
float: right;
margin-top: -2em;
}
input[type="submit"] {
display: inline-block;
background: @color-main;
color: #FFF;
border: 0;
padding: 0.6em 1em;
cursor: pointer;
}
input[type="submit"]:hover,
input[type="submit"]:focus {
background: @color-focus;
}
.row {
max-width: 60em;
margin: auto;
}
.row a {
color: @color-main;
}
.row form {
letter-spacing: -5px;
}
.row form > * { letter-spacing: normal; }
.row p { margin: 0; }
.row fieldset {
display: inline-block;
width: 48%;
vertical-align: top;
}
.row fieldset:last-of-type {
display: block;
width: auto;
background: none;
padding: 0;
}
.row fieldset:nth-child(odd) {
margin-right: 2%;
}
.row fieldset:nth-child(2) {
min-height: 10.5em;
}
@media screen and (max-width: 900px) {
.row {
margin: 0 1em;
}
.row fieldset { width: 49%; }
.row fieldset,
.row fieldset:nth-child(odd) {
margin-right: 0;
}
.row fieldset:first-child {
width: 100%;
margin-right: 0;
}
.row fieldset:nth-child(even) {
margin-right: 2%;
}
}
@media screen and (max-width: 800px) {
.row fieldset { width: 100%; }
select { width: 100%; }
table { font-size: 0.8em; }
.right {display: none;}
#sidebar { display: none; }
#results { padding: 0 2em; }
.search.center {
padding-right: 2em;
}
}
@media screen and (max-width: 400px) {
.row #categories_container > div {
width: 100%;
margin-left: 0;
}
}
fieldset {
border: 0;
margin: 1em 0;
background: #CCC;
padding: 1.5em;
}
table {
width: 100%;
text-align: left;
border: 1px solid #CCC;
border-collapse: collapse;
}
table th {
background: #999;
color: #FFF;
}
table tr:nth-child(odd) {
background: #CCC;
}
table th,
table td {
padding: 0.5em 1em;
border: 1px solid #FFF;
}
.engine_checkbox label {
padding: 0.5em;
background: @color-main;
color: #FFF;
cursor: pointer;
}
.engine_checkbox .deny {
background: @color-main;
}
.engine_checkbox .allow {
display: none;
background: #666;
}
.engine_checkbox input {
display: none;
}
.engine_checkbox input:checked + .allow {
display: inline;
}
.engine_checkbox input:checked + .allow + .deny{
display: none;
}
.row input[type="submit"] {
font-size: 1em;
margin: 1em 0 2em;
}
.row .right {
position: static;
display: inline-block;
}
.row .right a {
color: @color-fonts;
width: auto;
text-align: left;
padding: 0;
}
.small_font {
font-size: 0.8em;
}
table th {
padding: 1em;
}
legend {
background: #EEE;
padding: 0 1em;
position: relative;
}
select {
border: 1px solid #DDD;
padding: 0.5em 0.8em;
font-size: 1em;
}
.highlight .hll { background-color: #ffffcc }
.highlight { background: #f8f8f8; }
.highlight .c { color: #408080; font-style: italic } /* Comment */
.highlight .err { border: 1px solid #FF0000 } /* Error */
.highlight .k { color: #008000; font-weight: bold } /* Keyword */
.highlight .o { color: #666666 } /* Operator */
.highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */
.highlight .cp { color: #BC7A00 } /* Comment.Preproc */
.highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */
.highlight .cs { color: #408080; font-style: italic } /* Comment.Special */
.highlight .gd { color: #A00000 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #FF0000 } /* Generic.Error */
.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
.highlight .gi { color: #00A000 } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.highlight .gt { color: #0044DD } /* Generic.Traceback */
.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008000 } /* Keyword.Pseudo */
.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #B00040 } /* Keyword.Type */
.highlight .m { color: #666666 } /* Literal.Number */
.highlight .s { color: #BA2121 } /* Literal.String */
.highlight .na { color: #7D9029 } /* Name.Attribute */
.highlight .nb { color: #008000 } /* Name.Builtin */
.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */
.highlight .no { color: #880000 } /* Name.Constant */
.highlight .nd { color: #AA22FF } /* Name.Decorator */
.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */
.highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0000FF } /* Name.Function */
.highlight .nl { color: #A0A000 } /* Name.Label */
.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #19177C } /* Name.Variable */
.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mf { color: #666666 } /* Literal.Number.Float */
.highlight .mh { color: #666666 } /* Literal.Number.Hex */
.highlight .mi { color: #666666 } /* Literal.Number.Integer */
.highlight .mo { color: #666666 } /* Literal.Number.Oct */
.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */
.highlight .sc { color: #BA2121 } /* Literal.String.Char */
.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
.highlight .s2 { color: #BA2121 } /* Literal.String.Double */
.highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */
.highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
.highlight .sx { color: #008000 } /* Literal.String.Other */
.highlight .sr { color: #BB6688 } /* Literal.String.Regex */
.highlight .s1 { color: #BA2121 } /* Literal.String.Single */
.highlight .ss { color: #19177C } /* Literal.String.Symbol */
.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */
.highlight .vc { color: #19177C } /* Name.Variable.Class */
.highlight .vg { color: #19177C } /* Name.Variable.Global */
.highlight .vi { color: #19177C } /* Name.Variable.Instance */
.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
.highlight pre { overflow: auto; }
.highlight .lineno {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
cursor: default;
}
.highlight .lineno::selection { background: transparent; } /* WebKit/Blink Browsers */
.highlight .lineno::-moz-selection { background: transparent; } /* Gecko Browsers */

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@ -0,0 +1,83 @@
.highlight .hll { background-color: #ffffcc }
.highlight { background: #f8f8f8; }
.highlight .c { color: #408080; font-style: italic } /* Comment */
.highlight .err { border: 1px solid #FF0000 } /* Error */
.highlight .k { color: #008000; font-weight: bold } /* Keyword */
.highlight .o { color: #666666 } /* Operator */
.highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */
.highlight .cp { color: #BC7A00 } /* Comment.Preproc */
.highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */
.highlight .cs { color: #408080; font-style: italic } /* Comment.Special */
.highlight .gd { color: #A00000 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #FF0000 } /* Generic.Error */
.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
.highlight .gi { color: #00A000 } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.highlight .gt { color: #0044DD } /* Generic.Traceback */
.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008000 } /* Keyword.Pseudo */
.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #B00040 } /* Keyword.Type */
.highlight .m { color: #666666 } /* Literal.Number */
.highlight .s { color: #BA2121 } /* Literal.String */
.highlight .na { color: #7D9029 } /* Name.Attribute */
.highlight .nb { color: #008000 } /* Name.Builtin */
.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */
.highlight .no { color: #880000 } /* Name.Constant */
.highlight .nd { color: #AA22FF } /* Name.Decorator */
.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */
.highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0000FF } /* Name.Function */
.highlight .nl { color: #A0A000 } /* Name.Label */
.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #19177C } /* Name.Variable */
.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mf { color: #666666 } /* Literal.Number.Float */
.highlight .mh { color: #666666 } /* Literal.Number.Hex */
.highlight .mi { color: #666666 } /* Literal.Number.Integer */
.highlight .mo { color: #666666 } /* Literal.Number.Oct */
.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */
.highlight .sc { color: #BA2121 } /* Literal.String.Char */
.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
.highlight .s2 { color: #BA2121 } /* Literal.String.Double */
.highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */
.highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
.highlight .sx { color: #008000 } /* Literal.String.Other */
.highlight .sr { color: #BB6688 } /* Literal.String.Regex */
.highlight .s1 { color: #BA2121 } /* Literal.String.Single */
.highlight .ss { color: #19177C } /* Literal.String.Symbol */
.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */
.highlight .vc { color: #19177C } /* Name.Variable.Class */
.highlight .vg { color: #19177C } /* Name.Variable.Global */
.highlight .vi { color: #19177C } /* Name.Variable.Instance */
.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
.highlight pre {
overflow: auto;
}
.highlight .lineno {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
cursor: default;
&::selection {
background: transparent; /* WebKit/Blink Browsers */
}
&::-moz-selection {
background: transparent; /* Gecko Browsers */
}
}

View File

@ -15,6 +15,9 @@
/// General
@color-font: #444;
@color-font-light: #888;
@color-red: #C0392B;
@color-url-font: #1a11be;
@color-url-visited-font: #8E44AD;
@ -44,6 +47,9 @@
@color-autocompleter-choices-font: #444;
/// Answers
@color-answers-border: @color-base-dark;
// Selected
@color-autocompleter-selected-background: #444;
@color-autocompleter-selected-font: #FFF;
@ -78,10 +84,10 @@
@color-result-link-visited-font: @color-url-visited-font;
// Url to result
@color-result-url-font: #C0392B;
@color-result-url-font: @color-red;
// Publish Date
@color-result-publishdate-font: #888;
@color-result-publishdate-font: @color-font-light;
// Images
@color-result-image-span-background-hover: rgba(0, 0, 0, 0.6);
@ -109,5 +115,5 @@
/// Other
@color-engines-font: #888;
@color-engines-font: @color-font-light;
@color-percentage-div-background: #444;

View File

@ -8,6 +8,8 @@
@import "mixins.less";
@import "code.less";
// Main LESS-Code
html {
@ -342,6 +344,18 @@ a {
margin: 3px;
font-size: 0.8em;
}
a {
color: @color-result-link-font;
&:hover {
text-decoration: underline;
}
&:visited {
color: @color-result-link-visited-font;
}
}
}
.definition_result {
@ -434,6 +448,20 @@ tr {
}
#suggestions-title {
color: @color-font-light;
}
#answers {
border: 2px solid @color-answers-border;
padding: 20px;
}
#answers, #infoboxes {
form {
min-width: 210px;

View File

@ -1,22 +1 @@
html{position:relative;min-height:100%}
body{margin-bottom:80px}
.footer{position:absolute;bottom:0;width:100%;height:60px}
input[type=checkbox]:checked~.label_hide_if_checked{display:none}
input[type=checkbox]:not(:checked)~.label_hide_if_not_checked{display:none}
.result_header{margin-bottom:5px;margin-top:20px}.result_header .favicon{margin-bottom:-3px}
.result_header a{vertical-align:bottom}.result_header a .highlight{font-weight:bold}
.result-content{margin-top:5px}.result-content .highlight{font-weight:bold}
.result-default{clear:both}
.result-images{float:left !important}
.img-thumbnail{margin:5px;max-height:128px;min-height:128px}
.result-videos{clear:both}
.result-torrents{clear:both}
.result-map{clear:both}
.suggestion_item{margin:2px 5px}
.result_download{margin-right:5px}
#pagination{margin-top:30px;padding-bottom:50px}
.infobox .infobox_part{margin-bottom:20px}
.infobox .infobox_part:last-child{margin-bottom:0}
.search_categories{margin:10px 0;text-transform:capitalize}
.cursor-text{cursor:text !important}
.cursor-pointer{cursor:pointer !important}
html{position:relative;min-height:100%}body{margin-bottom:80px}.footer{position:absolute;bottom:0;width:100%;height:60px}input[type=checkbox]:checked+.label_hide_if_checked,input[type=checkbox]:checked+.label_hide_if_not_checked+.label_hide_if_checked{display:none}input[type=checkbox]:not(:checked)+.label_hide_if_not_checked,input[type=checkbox]:not(:checked)+.label_hide_if_checked+.label_hide_if_not_checked{display:none}.result_header{margin-bottom:5px;margin-top:20px}.result_header .favicon{margin-bottom:-3px}.result_header a{vertical-align:bottom}.result_header a .highlight{font-weight:bold}.result-content{margin-top:5px;word-wrap:break-word}.result-content .highlight{font-weight:bold}.result-default{clear:both}.result-images{float:left !important}.img-thumbnail{margin:5px;max-height:128px;min-height:128px}.result-videos{clear:both}.result-torrents{clear:both}.result-map{clear:both}.result-code{clear:both}.suggestion_item{margin:2px 5px}.result_download{margin-right:5px}#pagination{margin-top:30px;padding-bottom:50px}.infobox .infobox_part{margin-bottom:20px;word-wrap:break-word}.infobox .infobox_part:last-child{margin-bottom:0}.search_categories{margin:10px 0;text-transform:capitalize}.cursor-text{cursor:text !important}.cursor-pointer{cursor:pointer !important}.highlight .hll{background-color:#ffc}.highlight{background:#f8f8f8}.highlight .c{color:#408080;font-style:italic}.highlight .err{border:1px solid #f00}.highlight .k{color:#008000;font-weight:bold}.highlight .o{color:#666}.highlight .cm{color:#408080;font-style:italic}.highlight .cp{color:#bc7a00}.highlight .c1{color:#408080;font-style:italic}.highlight .cs{color:#408080;font-style:italic}.highlight .gd{color:#a00000}.highlight .ge{font-style:italic}.highlight .gr{color:#f00}.highlight .gh{color:#000080;font-weight:bold}.highlight .gi{color:#00a000}.highlight .go{color:#888}.highlight .gp{color:#000080;font-weight:bold}.highlight .gs{font-weight:bold}.highlight .gu{color:#800080;font-weight:bold}.highlight .gt{color:#04d}.highlight .kc{color:#008000;font-weight:bold}.highlight .kd{color:#008000;font-weight:bold}.highlight .kn{color:#008000;font-weight:bold}.highlight .kp{color:#008000}.highlight .kr{color:#008000;font-weight:bold}.highlight .kt{color:#b00040}.highlight .m{color:#666}.highlight .s{color:#ba2121}.highlight .na{color:#7d9029}.highlight .nb{color:#008000}.highlight .nc{color:#00f;font-weight:bold}.highlight .no{color:#800}.highlight .nd{color:#a2f}.highlight .ni{color:#999;font-weight:bold}.highlight .ne{color:#d2413a;font-weight:bold}.highlight .nf{color:#00f}.highlight .nl{color:#a0a000}.highlight .nn{color:#00f;font-weight:bold}.highlight .nt{color:#008000;font-weight:bold}.highlight .nv{color:#19177c}.highlight .ow{color:#a2f;font-weight:bold}.highlight .w{color:#bbb}.highlight .mf{color:#666}.highlight .mh{color:#666}.highlight .mi{color:#666}.highlight .mo{color:#666}.highlight .sb{color:#ba2121}.highlight .sc{color:#ba2121}.highlight .sd{color:#ba2121;font-style:italic}.highlight .s2{color:#ba2121}.highlight .se{color:#b62;font-weight:bold}.highlight .sh{color:#ba2121}.highlight .si{color:#b68;font-weight:bold}.highlight .sx{color:#008000}.highlight .sr{color:#b68}.highlight .s1{color:#ba2121}.highlight .ss{color:#19177c}.highlight .bp{color:#008000}.highlight .vc{color:#19177c}.highlight .vg{color:#19177c}.highlight .vi{color:#19177c}.highlight .il{color:#666}.highlight .lineno{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.highlight .lineno::selection{background:transparent}.highlight .lineno::-moz-selection{background:transparent}

View File

@ -33,9 +33,43 @@ module.exports = function(grunt) {
}
}
},
less: {
development: {
options: {
paths: ["less/oscar"]
//banner: '/*! less/oscar/oscar.css | <%= grunt.template.today("dd-mm-yyyy") %> | https://github.com/asciimoo/searx */\n'
},
files: {"css/oscar.css": "less/oscar/oscar.less"}
},
production: {
options: {
paths: ["less/oscar"],
//banner: '/*! less/oscar/oscar.css | <%= grunt.template.today("dd-mm-yyyy") %> | https://github.com/asciimoo/searx */\n',
cleancss: true
},
files: {"css/oscar.min.css": "less/oscar/oscar.less"}
},
bootstrap: {
options: {
paths: ["less/bootstrap"],
cleancss: true
},
files: {"css/bootstrap.min.css": "less/bootstrap/bootstrap.less"}
},
},
watch: {
files: ['<%= jshint.files %>'],
tasks: ['jshint']
scripts: {
files: ['<%= jshint.files %>'],
tasks: ['jshint', 'concat', 'uglify']
},
oscar_styles: {
files: ['less/oscar/**/*.less'],
tasks: ['less:development', 'less:production']
},
bootstrap_styles: {
files: ['less/bootstrap/**/*.less'],
tasks: ['less:bootstrap']
}
}
});
@ -43,9 +77,12 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-less');
grunt.registerTask('test', ['jshint']);
grunt.registerTask('default', ['jshint', 'concat', 'uglify']);
grunt.registerTask('default', ['jshint', 'concat', 'uglify', 'less']);
grunt.registerTask('styles', ['less']);
};

File diff suppressed because one or more lines are too long

View File

@ -1,9 +1,9 @@
// Hide element if checkbox is checked
input[type=checkbox]:checked ~ .label_hide_if_checked {
input[type=checkbox]:checked + .label_hide_if_checked, input[type=checkbox]:checked + .label_hide_if_not_checked + .label_hide_if_checked {
display:none;
}
// Hide element if checkbox is not checked
input[type=checkbox]:not(:checked) ~ .label_hide_if_not_checked {
input[type=checkbox]:not(:checked) + .label_hide_if_not_checked, input[type=checkbox]:not(:checked) + .label_hide_if_checked + .label_hide_if_not_checked {
display:none;
}

View File

@ -0,0 +1,79 @@
.highlight .hll { background-color: #ffffcc }
.highlight { background: #f8f8f8; }
.highlight .c { color: #408080; font-style: italic } /* Comment */
.highlight .err { border: 1px solid #FF0000 } /* Error */
.highlight .k { color: #008000; font-weight: bold } /* Keyword */
.highlight .o { color: #666666 } /* Operator */
.highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */
.highlight .cp { color: #BC7A00 } /* Comment.Preproc */
.highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */
.highlight .cs { color: #408080; font-style: italic } /* Comment.Special */
.highlight .gd { color: #A00000 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #FF0000 } /* Generic.Error */
.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
.highlight .gi { color: #00A000 } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.highlight .gt { color: #0044DD } /* Generic.Traceback */
.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008000 } /* Keyword.Pseudo */
.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #B00040 } /* Keyword.Type */
.highlight .m { color: #666666 } /* Literal.Number */
.highlight .s { color: #BA2121 } /* Literal.String */
.highlight .na { color: #7D9029 } /* Name.Attribute */
.highlight .nb { color: #008000 } /* Name.Builtin */
.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */
.highlight .no { color: #880000 } /* Name.Constant */
.highlight .nd { color: #AA22FF } /* Name.Decorator */
.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */
.highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0000FF } /* Name.Function */
.highlight .nl { color: #A0A000 } /* Name.Label */
.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #19177C } /* Name.Variable */
.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mf { color: #666666 } /* Literal.Number.Float */
.highlight .mh { color: #666666 } /* Literal.Number.Hex */
.highlight .mi { color: #666666 } /* Literal.Number.Integer */
.highlight .mo { color: #666666 } /* Literal.Number.Oct */
.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */
.highlight .sc { color: #BA2121 } /* Literal.String.Char */
.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
.highlight .s2 { color: #BA2121 } /* Literal.String.Double */
.highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */
.highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
.highlight .sx { color: #008000 } /* Literal.String.Other */
.highlight .sr { color: #BB6688 } /* Literal.String.Regex */
.highlight .s1 { color: #BA2121 } /* Literal.String.Single */
.highlight .ss { color: #19177C } /* Literal.String.Symbol */
.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */
.highlight .vc { color: #19177C } /* Name.Variable.Class */
.highlight .vg { color: #19177C } /* Name.Variable.Global */
.highlight .vi { color: #19177C } /* Name.Variable.Instance */
.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
.highlight .lineno {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
cursor: default;
&::selection {
background: transparent; /* WebKit/Blink Browsers */
}
&::-moz-selection {
background: transparent; /* Gecko Browsers */
}
}

View File

@ -1,6 +1,7 @@
.infobox {
.infobox_part {
margin-bottom: 20px;
word-wrap: break-word;
}
.infobox_part:last-child {

View File

@ -9,3 +9,5 @@
@import "search.less";
@import "cursor.less";
@import "code.less";

View File

@ -18,6 +18,7 @@
.result-content {
margin-top: 5px;
word-wrap: break-word;
.highlight {
font-weight:bold;
@ -55,6 +56,11 @@
clear: both;
}
// code formating of results
.result-code {
clear: both;
}
// suggestion
.suggestion_item {
margin: 2px 5px;

View File

@ -4,7 +4,8 @@
"grunt-contrib-uglify": "~0.6.0",
"grunt-contrib-watch" : "~0.6.1",
"grunt-contrib-concat" : "~0.5.0",
"grunt-contrib-jshint" : "~0.10.0"
"grunt-contrib-jshint" : "~0.10.0",
"grunt-contrib-less" : "~0.11.0"
},
"scripts": {

View File

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

View File

@ -1,33 +1,39 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<meta charset="UTF-8" />
<meta name="description" content="Searx - a privacy-respecting, hackable metasearch engine" />
<meta name="keywords" content="searx, search, search engine, metasearch, meta search" />
<meta name="generator" content="searx/{{ searx_version }}">
<meta name="viewport" content="width=device-width, maximum-scale=1.0, user-scalable=1" />
<title>{% block title %}{% endblock %}searx</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}" type="text/css" media="screen" />
<link rel="shortcut icon" href="{{ url_for('static', filename='img/favicon.png') }}?v=2" />
{% block styles %}
{% endblock %}
{% block head %}
<link title="searx" type="application/opensearchdescription+xml" rel="search" href="{{ url_for('opensearch') }}"/>
{% endblock %}
<script type="text/javascript">
searx = {};
searx.autocompleter = {% if autocomplete %}true{% else %}false{% endif %};
</script>
</head>
<body>
<div id="container">
{% block content %}
{% endblock %}
{% if autocomplete %}
<script src="{{ url_for('static', filename='js/mootools-core-1.4.5-min.js') }}" ></script>
<script src="{{ url_for('static', filename='js/mootools-autocompleter-1.1.2-min.js') }}" ></script>
{% endif %}
<script src="{{ url_for('static', filename='js/searx.js') }}" ></script>
</div>
</body>
</html>
<head>
<meta charset="UTF-8" />
<meta name="description" content="Searx - a privacy-respecting, hackable metasearch engine" />
<meta name="keywords" content="searx, search, search engine, metasearch, meta search" />
<meta name="generator" content="searx/{{ searx_version }}">
<meta name="viewport" content="width=device-width, maximum-scale=1.0, user-scalable=1" />
<title>{% block title %}{% endblock %}searx</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}" type="text/css" media="screen" />
{% if cookies['courgette-color'] %}
<style type="text/css">
{% include 'courgette/color.css' %}
</style>
{% endif %}
<link rel="shortcut icon" href="{{ url_for('static', filename='img/favicon.png') }}?v=2" />
{% block styles %}
{% endblock %}
{% block meta %}{% endblock %}
{% block head %}
<link title="searx" type="application/opensearchdescription+xml" rel="search" href="{{ url_for('opensearch') }}"/>
{% endblock %}
<script type="text/javascript">
searx = {};
searx.autocompleter = {% if autocomplete %}true{% else %}false{% endif %};
</script>
</head>
<body>
<div id="container">
{% block content %}
{% endblock %}
{% if autocomplete %}
<script src="{{ url_for('static', filename='js/mootools-core-1.4.5-min.js') }}" ></script>
<script src="{{ url_for('static', filename='js/mootools-autocompleter-1.1.2-min.js') }}" ></script>
{% endif %}
<script src="{{ url_for('static', filename='js/searx.js') }}" ></script>
</div>
</body>
</html>

View File

@ -1,7 +1,9 @@
<div id="categories">
{% for category in categories %}
<div class="checkbox_container">
<input type="checkbox" id="checkbox_{{ category|replace(' ', '_') }}" name="category_{{ category }}" {% if category in selected_categories %}checked="checked"{% endif %} /><label for="checkbox_{{ category|replace(' ', '_') }}">{{ _(category) }}</label>
<div id="categories_container">
{% for category in categories %}
<div class="checkbox_container">
<input type="checkbox" id="checkbox_{{ category|replace(' ', '_') }}" name="category_{{ category }}" {% if category in selected_categories %}checked="checked"{% endif %} /><label for="checkbox_{{ category|replace(' ', '_') }}">{{ _(category) }}</label>
</div>
{% endfor %}
</div>
{% endfor %}
</div>
</div>

View File

@ -0,0 +1,34 @@
.autocompleter-choices li:hover,
.checkbox_container label:hover,
.checkbox_container input[type="checkbox"]:checked + label,
#sidebar,
#suggestions input[type="submit"]:hover,
#suggestions input[type="submit"]:focus,
input[type="submit"],
.engine_checkbox label,
.engine_checkbox .deny,
#search_submit{
background-color: {{ cookies['courgette-color'].split()[0] }};
}
.result_title a,
.row a,
.title h1{
color: {{ cookies['courgette-color'].split()[0] }};
}
#answers {
border-color: {{ cookies['courgette-color'].split()[0] }};
}
#search_submit:hover,
#search_submit:focus,
#sidebar input[type="submit"]:hover,
#sidebar input[type="submit"]:focus {
background-color: {{ cookies['courgette-color'].split()[1] }};
}
input[type="submit"]:hover,
input[type="submit"]:focus {
background: {{ cookies['courgette-color'].split()[1] }};
}

View File

@ -1,3 +1,3 @@
<a href="https://github.com/asciimoo/searx" class="github">
<img style="position: absolute; top: 0; right: 0; border: 0;" src="{{ url_for('static', filename='img/github_ribbon.png') }}" alt="Fork me on GitHub" class="github"/>
</a>
</a>

View File

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

View File

@ -1,4 +1,4 @@
{% extends "default/base.html" %}
{% extends "courgette/base.html" %}
{% block head %} {% endblock %}
{% block content %}
<div class="row">
@ -7,95 +7,115 @@
<form method="post" action="{{ url_for('preferences') }}" id="search_form">
<fieldset>
<legend>{{ _('Default categories') }}</legend>
<p>
{% include 'default/categories.html' %}
</p>
{% include 'courgette/categories.html' %}
</fieldset>
<fieldset>
<legend>{{ _('Search language') }}</legend>
<p>
<select name='language'>
<option value="all" {% if current_language == 'all' %}selected="selected"{% endif %}>{{ _('Automatic') }}</option>
{% for lang_id,lang_name,country_name in language_codes %}
<option value="{{ lang_id }}" {% if lang_id == current_language %}selected="selected"{% endif %}>{{ lang_name }} ({{ country_name }}) - {{ lang_id }}</option>
{% endfor %}
</select>
<select name='language'>
<option value="all" {% if current_language == 'all' %}selected="selected"{% endif %}>{{ _('Automatic') }}</option>
{% for lang_id,lang_name,country_name in language_codes %}
<option value="{{ lang_id }}" {% if lang_id == current_language %}selected="selected"{% endif %}>{{ lang_name }} ({{ country_name }}) - {{ lang_id }}</option>
{% endfor %}
</select>
</p>
</fieldset>
<fieldset>
<legend>{{ _('Interface language') }}</legend>
<p>
<select name='locale'>
{% for locale_id,locale_name in locales.items() %}
<option value="{{ locale_id }}" {% if locale_id == current_locale %}selected="selected"{% endif %}>{{ locale_name }}</option>
{% endfor %}
</select>
<select name='locale'>
{% for locale_id,locale_name in locales.items() %}
<option value="{{ locale_id }}" {% if locale_id == current_locale %}selected="selected"{% endif %}>{{ locale_name }}</option>
{% endfor %}
</select>
</p>
</fieldset>
<fieldset>
<legend>{{ _('Autocomplete') }}</legend>
<p>
<select name="autocomplete">
<option value=""> - </option>
{% for backend in autocomplete_backends %}
<option value="{{ backend }}" {% if backend == autocomplete %}selected="selected"{% endif %}>{{ backend }}</option>
{% endfor %}
</select>
<select name="autocomplete">
<option value=""> - </option>
{% for backend in autocomplete_backends %}
<option value="{{ backend }}" {% if backend == autocomplete %}selected="selected"{% endif %}>{{ backend }}</option>
{% endfor %}
</select>
</p>
</fieldset>
<fieldset>
<legend>{{ _('Image proxy') }}</legend>
<p>
<select name='image_proxy'>
<option value="1" {% if image_proxy %}selected="selected"{% endif %}>{{ _('Enabled') }}</option>
<option value="" {% if not image_proxy %}selected="selected"{% endif %}>{{ _('Disabled') }}</option>
</select>
</p>
</fieldset>
<fieldset>
<legend>{{ _('Method') }}</legend>
<p>
<select name='method'>
<option value="POST" {% if method == 'POST' %}selected="selected"{% endif %}>POST</option>
<option value="GET" {% if method == 'GET' %}selected="selected"{% endif %}>GET</option>
</select>
<select name='method'>
<option value="POST" {% if method == 'POST' %}selected="selected"{% endif %}>POST</option>
<option value="GET" {% if method == 'GET' %}selected="selected"{% endif %}>GET</option>
</select>
</p>
</fieldset>
<fieldset>
<legend>{{ _('Themes') }}</legend>
<p>
<select name="theme">
{% for name in themes %}
<option value="{{ name }}" {% if name == theme %}selected="selected"{% endif %}>{{ name }}</option>
{% endfor %}
</select>
<select name="theme">
{% for name in themes %}
<option value="{{ name }}" {% if name == theme %}selected="selected"{% endif %}>{{ name }}</option>
{% endfor %}
</select>
</p>
</fieldset>
<fieldset>
<legend>{{ _('Currently used search engines') }}</legend>
<legend>{{ _('Color') }}</legend>
<p>
<select name="courgette-color">
<option value="#3498DB #0665A2" {% if cookies['courgette-color'] and cookies['courgette-color'] == '#3498DB #0665A2' %}selected="selected"{% endif %}>{{ _('Blue (default)') }}</option>
<option value="#6F5499 #563D7C" {% if cookies['courgette-color'] and cookies['courgette-color'] == '#6F5499 #563D7C' %}selected="selected"{% endif %}>{{ _('Violet') }}</option>
<option value="#5CB85C #449D44" {% if cookies['courgette-color'] and cookies['courgette-color'] == '#5CB85C #449D44' %}selected="selected"{% endif %}>{{ _('Green') }}</option>
<option value="#5BC0DE #31B0D5" {% if cookies['courgette-color'] and cookies['courgette-color'] == '#5BC0DE #31B0D5' %}selected="selected"{% endif %}>{{ _('Cyan') }}</option>
<option value="#F0AD4E #EC971F" {% if cookies['courgette-color'] and cookies['courgette-color'] == '#F0AD4E #EC971F' %}selected="selected"{% endif %}>{{ _('Orange') }}</option>
<option value="#D9534F #C9302C" {% if cookies['courgette-color'] and cookies['courgette-color'] == '#D9534F #C9302C' %}selected="selected"{% endif %}>{{ _('Red') }}</option>
</select>
</p>
</fieldset>
<fieldset>
<legend>{{ _('Currently used search engines') }}</legend>
<table>
<tr>
<th>{{ _('Engine name') }}</th>
<th>{{ _('Category') }}</th>
<th>{{ _('Allow') }} / {{ _('Block') }}</th>
</tr>
{% for (categ,search_engines) in categs %}
{% for search_engine in search_engines %}
{% if not search_engine.private %}
<table>
<tr>
<td>{{ search_engine.name }} ({{ shortcuts[search_engine.name] }})</td>
<td>{{ _(categ) }}</td>
<td class="engine_checkbox">
<input type="checkbox" id="engine_{{ categ }}_{{ search_engine.name|replace(' ', '_') }}" name="engine_{{ search_engine.name }}"{% if search_engine.name in blocked_engines %} checked="checked"{% endif %} />
<label class="allow" for="engine_{{ categ }}_{{ search_engine.name|replace(' ', '_') }}">{{ _('Allow') }}</label>
<label class="deny" for="engine_{{ categ }}_{{ search_engine.name|replace(' ', '_') }}">{{ _('Block') }}</label>
</td>
<th>{{ _('Engine name') }}</th>
<th>{{ _('Category') }}</th>
<th>{{ _('Allow') }} / {{ _('Block') }}</th>
</tr>
{% endif %}
{% for (categ,search_engines) in categs %}
{% for search_engine in search_engines %}
{% if not search_engine.private %}
<tr>
<td>{{ search_engine.name }} ({{ shortcuts[search_engine.name] }})</td>
<td>{{ _(categ) }}</td>
<td class="engine_checkbox">
<input type="checkbox" id="engine_{{ categ|replace(' ', '_') }}_{{ search_engine.name|replace(' ', '_') }}" name="engine_{{ search_engine.name }}__{{ categ }}"{% if (search_engine.name, categ) in blocked_engines %} checked="checked"{% endif %} />
<label class="allow" for="engine_{{ categ|replace(' ', '_') }}_{{ search_engine.name|replace(' ', '_') }}">{{ _('Allow') }}</label>
<label class="deny" for="engine_{{ categ|replace(' ', '_') }}_{{ search_engine.name|replace(' ', '_') }}">{{ _('Block') }}</label>
</td>
</tr>
{% endif %}
{% endfor %}
{% endfor %}
{% endfor %}
</table>
</table>
</fieldset>
<p class="small_font">{{ _('These settings are stored in your cookies, this allows us not to store this data about you.') }}
<br />
{{ _("These cookies serve your sole convenience, we don't use these cookies to track you.") }}
<br />
{{ _("These cookies serve your sole convenience, we don't use these cookies to track you.") }}
</p>
<input type="submit" value="{{ _('save') }}" />
<div class="right preferences_back"><a href="{{ url_for('index') }}">{{ _('back') }}</a></div>
<div class="right preferences_back"><a href="{{ url_for('index') }}">{{ _('back') }}</a></div>
</form>
</div>
{% endblock %}

View File

@ -0,0 +1,9 @@
<div class="result {{ result.class }}">
<h3 class="result_title">{% if result['favicon'] %}<img width="14" height="14" class="favicon" src="static/{{theme}}/img/icon_{{result['favicon']}}.ico" alt="{{result['favicon']}}" />{% endif %}<a href="{{ result.url }}">{{ result.title|safe }}</a></h3>
{% if result.publishedDate %}<span class="published_date">{{ result.publishedDate }}</span>{% endif %}
<p class="content">{% if result.img_src %}<img src="{{ image_proxify(result.img_src) }}" class="image" />{% endif %}{% if result.content %}{{ result.content|safe }}<br class="last"/>{% endif %}</p>
{% if result.repository %}<p class="content"><a href="{{ result.repository|safe }}">{{ result.repository }}</a></p>{% endif %}
{{ result.codelines|code_highlighter(result.code_language)|safe }}
<p class="url">{{ result.pretty_url }}</p>
</div>

View File

@ -1,13 +1,13 @@
<div class="result {{ result.class }}">
{% if "icon_"~result.engine~".ico" in favicons %}
{% if "icon_"~result.engine~".ico" in favicons %}
<img width="14" height="14" class="favicon" src="{{ url_for('static', filename='img/icons/icon_'+result.engine+'.ico') }}" alt="{{result.engine}}" />
{% endif %}
{% endif %}
<div>
<h3 class="result_title"><a href="{{ result.url }}">{{ result.title|safe }}</a></h3>
{% if result.publishedDate %}<p class="published_date">{{ result.publishedDate }}</p>{% endif %}
<p class="content">{% if result.content %}{{ result.content|safe }}<br />{% endif %}</p>
<p class="url">{{ result.pretty_url }}</p>
</div>
</div>
<div>
<h3 class="result_title"><a href="{{ result.url }}">{{ result.title|safe }}</a></h3>
{% if result.publishedDate %}<span class="published_date">{{ result.publishedDate }}</span>{% endif %}
<p class="content">{% if result.content %}{{ result.content|safe }}<br />{% endif %}</p>
<p class="url">{{ result.pretty_url }}</p>
</div>
</div>

View File

@ -1,6 +1,6 @@
<div class="image_result">
<p>
<a href="{{ result.img_src }}"><img src="{{ result.img_src }}" title="{{ result.title|striptags }}" alt="{{ result.title|striptags }}"/></a>
<span class="url"><a href="{{ result.url }}" class="small_font">original context</a></span>
<a href="{{ result.img_src }}"><img src="{% if result.thumbnail_src %}{{ image_proxify(result.thumbnail_src) }}{% else %}{{ image_proxify(result.img_src) }}{% endif %}" title="{{ result.title|striptags }}" alt="{{ result.title|striptags }}"/></a>
<span class="url"><a href="{{ result.url }}" class="small_font">{{ _('original context') }}</a></span>
</p>
</div>

View File

@ -1,13 +1,13 @@
<div class="result {{ result.class }}">
{% if "icon_"~result.engine~".ico" in favicons %}
<img width="14" height="14" class="favicon" src="{{ url_for('static', filename='img/icons/icon_'+result.engine+'.ico') }}" alt="{{result.engine}}" />
{% endif %}
{% if "icon_"~result.engine~".ico" in favicons %}
<img width="14" height="14" class="favicon" src="{{ url_for('static', filename='img/icons/icon_'+result.engine+'.ico') }}" alt="{{result.engine}}" />
{% endif %}
<div>
<h3 class="result_title"><a href="{{ result.url }}">{{ result.title|safe }}</a></h3>
{% if result.publishedDate %}<p class="published_date">{{ result.publishedDate }}</p>{% endif %}
<p class="content">{% if result.content %}{{ result.content|safe }}<br />{% endif %}</p>
<p class="url">{{ result.pretty_url }}</p>
</div>
</div>
<div>
<h3 class="result_title"><a href="{{ result.url }}">{{ result.title|safe }}</a></h3>
{% if result.publishedDate %}<span class="published_date">{{ result.publishedDate }}</span>{% endif %}
<p class="content">{% if result.content %}{{ result.content|safe }}<br />{% endif %}</p>
<p class="url">{{ result.pretty_url }}</p>
</div>
</div>

View File

@ -1,7 +1,13 @@
<div class="result torrent_result">
{% if "icon_"~result.engine~".ico" in favicons %}
<img width="14" height="14" class="favicon" src="{{ url_for('static', filename='img/icons/icon_'+result.engine+'.ico') }}" alt="{{result.engine}}" />
{% endif %}
<h3 class="result_title"><a href="{{ result.url }}">{{ result.title|safe }}</a></h3>
{% if result.content %}<p class="content">{{ result.content|safe }}</p>{% endif %}
<p class="stats">Seed: {{ result.seed }}, Leech: {{ result.leech }}</p>
<p><a href="{{ result.magnetlink }}" class="magnetlink">magnet link</a></p>
{% if result.content %}<span class="content">{{ result.content|safe }}</span><br />{% endif %}
<span class="stats">{{ _('Seeder') }} : {{ result.seed }}, {{ _('Leecher') }} : {{ result.leech }}</span><br />
<span>
{% if result.magnetlink %}<a href="{{ result.magnetlink }}" class="magnetlink">{{ _('magnet link') }}</a>{% endif %}
{% if result.torrentfile %}<a href="{{ result.torrentfile }}" class="torrentfile">{{ _('torrent file') }}</a>{% endif %}
</span>
<p class="url">{{ result.pretty_url }}</p>
</div>
</div>

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