logo

searx

My custom branche(s) on searx, a meta-search engine
commit: 7369fbd54c7a4441065490d2940e6de129cb1b98
parent: 3386e21cdf30bf0accb84e2dcc4dea0076af1b90
Author: Adam Tauber <asciimoo@gmail.com>
Date:   Tue, 10 Jun 2014 01:18:37 +0200

Merge pull request #70 from matejc/theming_support

add multi theming support

Diffstat:

MMakefile4++--
Msearx/settings.yml2++
Rsearx/static/css/style.css -> searx/static/default/css/style.css0
Rsearx/static/img/favicon.png -> searx/static/default/img/favicon.png0
Rsearx/static/img/github_ribbon.png -> searx/static/default/img/github_ribbon.png0
Rsearx/static/img/icon_github.ico -> searx/static/default/img/icon_github.ico0
Rsearx/static/img/icon_soundcloud.ico -> searx/static/default/img/icon_soundcloud.ico0
Rsearx/static/img/icon_stackoverflow.ico -> searx/static/default/img/icon_stackoverflow.ico0
Rsearx/static/img/icon_twitter.ico -> searx/static/default/img/icon_twitter.ico0
Rsearx/static/img/icon_vimeo.ico -> searx/static/default/img/icon_vimeo.ico0
Rsearx/static/img/icon_wikipedia.ico -> searx/static/default/img/icon_wikipedia.ico0
Rsearx/static/img/icon_youtube.ico -> searx/static/default/img/icon_youtube.ico0
Rsearx/static/img/preference-icon.png -> searx/static/default/img/preference-icon.png0
Rsearx/static/img/search-icon.png -> searx/static/default/img/search-icon.png0
Rsearx/static/img/searx.png -> searx/static/default/img/searx.png0
Rsearx/static/img/searx_logo.svg -> searx/static/default/img/searx_logo.svg0
Rsearx/static/js/mootools-autocompleter-1.1.2-min.js -> searx/static/default/js/mootools-autocompleter-1.1.2-min.js0
Rsearx/static/js/mootools-core-1.4.5-min.js -> searx/static/default/js/mootools-core-1.4.5-min.js0
Rsearx/static/js/searx.js -> searx/static/default/js/searx.js0
Rsearx/static/less/autocompleter.less -> searx/static/default/less/autocompleter.less0
Rsearx/static/less/definitions.less -> searx/static/default/less/definitions.less0
Rsearx/static/less/mixins.less -> searx/static/default/less/mixins.less0
Rsearx/static/less/search.less -> searx/static/default/less/search.less0
Rsearx/static/less/style.less -> searx/static/default/less/style.less0
Dsearx/templates/about.html66------------------------------------------------------------------
Asearx/templates/default/about.html66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rsearx/templates/base.html -> searx/templates/default/base.html0
Rsearx/templates/categories.html -> searx/templates/default/categories.html0
Rsearx/templates/github_ribbon.html -> searx/templates/default/github_ribbon.html0
Asearx/templates/default/index.html11+++++++++++
Rsearx/templates/opensearch.xml -> searx/templates/default/opensearch.xml0
Rsearx/templates/opensearch_response_rss.xml -> searx/templates/default/opensearch_response_rss.xml0
Asearx/templates/default/preferences.html101+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asearx/templates/default/result_templates/default.html13+++++++++++++
Rsearx/templates/result_templates/images.html -> searx/templates/default/result_templates/images.html0
Rsearx/templates/result_templates/torrent.html -> searx/templates/default/result_templates/torrent.html0
Asearx/templates/default/result_templates/videos.html12++++++++++++
Asearx/templates/default/results.html79+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asearx/templates/default/search.html7+++++++
Asearx/templates/default/stats.html22++++++++++++++++++++++
Dsearx/templates/index.html11-----------
Dsearx/templates/preferences.html91-------------------------------------------------------------------------------
Dsearx/templates/result_templates/default.html13-------------
Dsearx/templates/result_templates/videos.html12------------
Dsearx/templates/results.html79-------------------------------------------------------------------------------
Dsearx/templates/search.html7-------
Dsearx/templates/stats.html22----------------------
Msearx/utils.py22+++++++++++++++++++---
Msearx/webapp.py65++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
49 files changed, 390 insertions(+), 315 deletions(-)

diff --git a/Makefile b/Makefile @@ -44,13 +44,13 @@ minimal: bin/buildout minimal.cfg setup.py bin/buildout -c minimal.cfg $(options) styles: - @lessc -x searx/static/less/style.less > searx/static/css/style.css + @lessc -x searx/static/default/less/style.less > searx/static/default/css/style.css locales: @pybabel compile -d searx/translations clean: @rm -rf .installed.cfg .mr.developer.cfg bin parts develop-eggs \ - searx.egg-info lib include .coverage coverage searx/static/css/*.css + searx.egg-info lib include .coverage coverage searx/static/default/css/*.css .PHONY: all tests robot flake8 coverage production minimal styles locales clean diff --git a/searx/settings.yml b/searx/settings.yml @@ -4,6 +4,8 @@ server: debug : True request_timeout : 2.0 # seconds base_url : False + themes_path : "" + default_theme : default engines: - name : wikipedia diff --git a/searx/static/css/style.css b/searx/static/default/css/style.css diff --git a/searx/static/img/favicon.png b/searx/static/default/img/favicon.png Binary files differ. diff --git a/searx/static/img/github_ribbon.png b/searx/static/default/img/github_ribbon.png Binary files differ. diff --git a/searx/static/img/icon_github.ico b/searx/static/default/img/icon_github.ico Binary files differ. diff --git a/searx/static/img/icon_soundcloud.ico b/searx/static/default/img/icon_soundcloud.ico Binary files differ. diff --git a/searx/static/img/icon_stackoverflow.ico b/searx/static/default/img/icon_stackoverflow.ico Binary files differ. diff --git a/searx/static/img/icon_twitter.ico b/searx/static/default/img/icon_twitter.ico Binary files differ. diff --git a/searx/static/img/icon_vimeo.ico b/searx/static/default/img/icon_vimeo.ico Binary files differ. diff --git a/searx/static/img/icon_wikipedia.ico b/searx/static/default/img/icon_wikipedia.ico Binary files differ. diff --git a/searx/static/img/icon_youtube.ico b/searx/static/default/img/icon_youtube.ico Binary files differ. diff --git a/searx/static/img/preference-icon.png b/searx/static/default/img/preference-icon.png Binary files differ. diff --git a/searx/static/img/search-icon.png b/searx/static/default/img/search-icon.png Binary files differ. diff --git a/searx/static/img/searx.png b/searx/static/default/img/searx.png Binary files differ. diff --git a/searx/static/img/searx_logo.svg b/searx/static/default/img/searx_logo.svg diff --git a/searx/static/js/mootools-autocompleter-1.1.2-min.js b/searx/static/default/js/mootools-autocompleter-1.1.2-min.js diff --git a/searx/static/js/mootools-core-1.4.5-min.js b/searx/static/default/js/mootools-core-1.4.5-min.js diff --git a/searx/static/js/searx.js b/searx/static/default/js/searx.js diff --git a/searx/static/less/autocompleter.less b/searx/static/default/less/autocompleter.less diff --git a/searx/static/less/definitions.less b/searx/static/default/less/definitions.less diff --git a/searx/static/less/mixins.less b/searx/static/default/less/mixins.less diff --git a/searx/static/less/search.less b/searx/static/default/less/search.less diff --git a/searx/static/less/style.less b/searx/static/default/less/style.less diff --git a/searx/templates/about.html b/searx/templates/about.html @@ -1,66 +0,0 @@ -{% extends 'base.html' %} -{% block content %} -{% include 'github_ribbon.html' %} -<div class="row"> - <h1>About <a href="{{ url_for('index') }}">searx</a></h1> - - <p>Searx is a <a href="https://en.wikipedia.org/wiki/Metasearch_engine">metasearch engine</a>, aggregating the results of other <a href="{{ url_for('preferences') }}">search engines</a> while not storing information about its users. - </p> - <h2>Why use Searx?</h2> - <ul> - <li>Searx may not offer you as personalised results as Google, but it doesn't generate a profile about you</li> - <li>Searx doesn't care about what you search for, never shares anything with a third party, and it can't be used to compromise you</li> - <li>Searx is free software, the code is 100% open and you can help to make it better. See more on <a href="https://github.com/asciimoo/searx">github</a></li> - </ul> - <p>If you do care about privacy, want to be a conscious user, or otherwise believe - in digital freedom, make Searx your default search engine or run it on your own server</p> - -<h2>Technical details - How does it work?</h2> - -<p>Searx is a <a href="https://en.wikipedia.org/wiki/Metasearch_engine">metasearch engine</a>, -inspired by the <a href="http://seeks-project.info/">seeks project</a>.<br /> -It provides basic privacy by mixing your queries with searches on other platforms without storing search data. Queries are made using a POST request on every browser (except chrome*). Therefore they show up in neither our logs, nor your url history. In case of Chrome* users there is an exception, Searx uses the search bar to perform GET requests.<br /> -Searx can be added to your browser's search bar; moreover, it can be set as the default search engine. -</p> - -<h2>How can I make it my own?</h2> - -<p>Searx appreciates your concern regarding logs, so take the <a href="https://github.com/asciimoo/searx">code</a> and run it yourself! <br />Add your Searx to this <a href="https://github.com/asciimoo/searx/wiki/Searx-instances">list</a> to help other people reclaim their privacy and make the Internet freer! -<br />The more decentralized the Internet, is the more freedom we have!</p> - - -<h2>More about searx</h2> - -<ul> - <li><a href="https://github.com/asciimoo/searx">github</a></li> - <li><a href="https://www.ohloh.net/p/searx/">ohloh</a></li> - <li><a href="https://twitter.com/Searx_engine">twitter</a></li> - <li>IRC: #searx @ freenode (<a href="https://kiwiirc.com/client/irc.freenode.com/searx">webclient</a>)</li> - <li><a href="https://www.transifex.com/projects/p/searx/">transifex</a></li> -</ul> - - -<hr /> - -<h2 id="faq">FAQ</h2> - -<h3>How to add to firefox?</h3> -<p><a href="#" onclick="window.external.AddSearchProvider(window.location.protocol + '//' + window.location.host + '{{ url_for('opensearch') }}');">Install</a> searx as a search engine on any version of Firefox! (javascript required)</p> - -<h2 id="dev_faq">Developer FAQ</h2> - -<h3>New engines?</h3> -<ul> - <li>Edit your <a href="https://raw.github.com/asciimoo/searx/master/searx/settings.yml">settings.yml</a></li> - <li>Create your custom engine module, check the <a href="https://github.com/asciimoo/searx/blob/master/examples/basic_engine.py">example engine</a></li> -</ul> -<p>Don't forget to restart searx after config edit!</p> - -<h3>Installation/WSGI support?</h3> -<p>See the <a href="https://github.com/asciimoo/searx/wiki/Installation">installation and setup</a> wiki page</p> - -<h3>How to debug engines?</h3> -<p><a href="{{ url_for('stats') }}">Stats page</a> contains some useful data about the engines used.</p> - -</div> -{% endblock %} diff --git a/searx/templates/default/about.html b/searx/templates/default/about.html @@ -0,0 +1,66 @@ +{% extends 'default/base.html' %} +{% block content %} +{% include 'default/github_ribbon.html' %} +<div class="row"> + <h1>About <a href="{{ url_for('index') }}">searx</a></h1> + + <p>Searx is a <a href="https://en.wikipedia.org/wiki/Metasearch_engine">metasearch engine</a>, aggregating the results of other <a href="{{ url_for('preferences') }}">search engines</a> while not storing information about its users. + </p> + <h2>Why use Searx?</h2> + <ul> + <li>Searx may not offer you as personalised results as Google, but it doesn't generate a profile about you</li> + <li>Searx doesn't care about what you search for, never shares anything with a third party, and it can't be used to compromise you</li> + <li>Searx is free software, the code is 100% open and you can help to make it better. See more on <a href="https://github.com/asciimoo/searx">github</a></li> + </ul> + <p>If you do care about privacy, want to be a conscious user, or otherwise believe + in digital freedom, make Searx your default search engine or run it on your own server</p> + +<h2>Technical details - How does it work?</h2> + +<p>Searx is a <a href="https://en.wikipedia.org/wiki/Metasearch_engine">metasearch engine</a>, +inspired by the <a href="http://seeks-project.info/">seeks project</a>.<br /> +It provides basic privacy by mixing your queries with searches on other platforms without storing search data. Queries are made using a POST request on every browser (except chrome*). Therefore they show up in neither our logs, nor your url history. In case of Chrome* users there is an exception, Searx uses the search bar to perform GET requests.<br /> +Searx can be added to your browser's search bar; moreover, it can be set as the default search engine. +</p> + +<h2>How can I make it my own?</h2> + +<p>Searx appreciates your concern regarding logs, so take the <a href="https://github.com/asciimoo/searx">code</a> and run it yourself! <br />Add your Searx to this <a href="https://github.com/asciimoo/searx/wiki/Searx-instances">list</a> to help other people reclaim their privacy and make the Internet freer! +<br />The more decentralized the Internet, is the more freedom we have!</p> + + +<h2>More about searx</h2> + +<ul> + <li><a href="https://github.com/asciimoo/searx">github</a></li> + <li><a href="https://www.ohloh.net/p/searx/">ohloh</a></li> + <li><a href="https://twitter.com/Searx_engine">twitter</a></li> + <li>IRC: #searx @ freenode (<a href="https://kiwiirc.com/client/irc.freenode.com/searx">webclient</a>)</li> + <li><a href="https://www.transifex.com/projects/p/searx/">transifex</a></li> +</ul> + + +<hr /> + +<h2 id="faq">FAQ</h2> + +<h3>How to add to firefox?</h3> +<p><a href="#" onclick="window.external.AddSearchProvider(window.location.protocol + '//' + window.location.host + '{{ url_for('opensearch') }}');">Install</a> searx as a search engine on any version of Firefox! (javascript required)</p> + +<h2 id="dev_faq">Developer FAQ</h2> + +<h3>New engines?</h3> +<ul> + <li>Edit your <a href="https://raw.github.com/asciimoo/searx/master/searx/settings.yml">settings.yml</a></li> + <li>Create your custom engine module, check the <a href="https://github.com/asciimoo/searx/blob/master/examples/basic_engine.py">example engine</a></li> +</ul> +<p>Don't forget to restart searx after config edit!</p> + +<h3>Installation/WSGI support?</h3> +<p>See the <a href="https://github.com/asciimoo/searx/wiki/Installation">installation and setup</a> wiki page</p> + +<h3>How to debug engines?</h3> +<p><a href="{{ url_for('stats') }}">Stats page</a> contains some useful data about the engines used.</p> + +</div> +{% endblock %} diff --git a/searx/templates/base.html b/searx/templates/default/base.html diff --git a/searx/templates/categories.html b/searx/templates/default/categories.html diff --git a/searx/templates/github_ribbon.html b/searx/templates/default/github_ribbon.html diff --git a/searx/templates/default/index.html b/searx/templates/default/index.html @@ -0,0 +1,11 @@ +{% extends "default/base.html" %} +{% block content %} +<div class="center"> + <div class="title"><h1>searx</h1></div> + {% include 'default/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 %} diff --git a/searx/templates/opensearch.xml b/searx/templates/default/opensearch.xml diff --git a/searx/templates/opensearch_response_rss.xml b/searx/templates/default/opensearch_response_rss.xml diff --git a/searx/templates/default/preferences.html b/searx/templates/default/preferences.html @@ -0,0 +1,101 @@ +{% extends "default/base.html" %} +{% block head %} {% endblock %} +{% block content %} +<div class="row"> + <h2>{{ _('Preferences') }}</h2> + + <form method="post" action="{{ url_for('preferences') }}" id="search_form"> + <fieldset> + <legend>{{ _('Default categories') }}</legend> + <p> + {% include 'default/categories.html' %} + </p> + </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> + </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> + </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> + </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> + </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> + </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 %} + <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> + </tr> + {% endif %} + {% endfor %} + {% endfor %} + </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.") }} + </p> + + <input type="submit" value="{{ _('save') }}" /> + <div class="right preferences_back"><a href="{{ url_for('index') }}">{{ _('back') }}</a></div> + </form> +</div> +{% endblock %} diff --git a/searx/templates/default/result_templates/default.html b/searx/templates/default/result_templates/default.html @@ -0,0 +1,13 @@ +<div class="result {{ result.class }}"> + + {% if result['favicon'] %} + <img width="14" height="14" class="favicon" src="static/{{theme}}/img/icon_{{result['favicon']}}.ico" /> + {% 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> diff --git a/searx/templates/result_templates/images.html b/searx/templates/default/result_templates/images.html diff --git a/searx/templates/result_templates/torrent.html b/searx/templates/default/result_templates/torrent.html diff --git a/searx/templates/default/result_templates/videos.html b/searx/templates/default/result_templates/videos.html @@ -0,0 +1,12 @@ +<div class="result"> + {% if result['favicon'] %} + <img width="14" height="14" class="favicon" src="static/{{theme}}/img/icon_{{result['favicon']}}.ico" /> + {% endif %} + + <p> + <h3 class="result_title"><a href="{{ result.url }}">{{ result.title|safe }}</a></h3> + {% if result.publishedDate %}<p class="published_date">{{ result.publishedDate }}</p>{% endif %} + <a href="{{ result.url }}"><img width="400px" src="{{ result.thumbnail }}" title={{ result.title }} alt=" {{ result.title }}"/></a> + <p class="url">{{ result.url }}</p> + </p> +</div> diff --git a/searx/templates/default/results.html b/searx/templates/default/results.html @@ -0,0 +1,79 @@ +{% extends "default/base.html" %} +{% block title %}{{ q }} - {% endblock %} +{% block content %} +<div class="right"><a href="{{ url_for('preferences') }}" id="preferences"><span>preferences</span></a></div> +<div class="small search center"> + {% include 'default/search.html' %} +</div> +<div id="results"> + <div id="sidebar"> + + <div id="search_url"> + {{ _('Search URL') }}: + <input type="text" value="{{ base_url }}?q={{ q|urlencode }}&pageno={{ pageno }}{% if selected_categories %}&category_{{ selected_categories|join("&category_") }}{% endif %}" readonly="" /> + </div> + <div id="apis"> + {{ _('Download results') }} + {% for output_type in ('csv', 'json', 'rss') %} + <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}"> + <div class="left"> + <input type="hidden" name="q" value="{{ q }}" /> + <input type="hidden" name="format" value="{{ output_type }}" /> + {% for category in selected_categories %} + <input type="hidden" name="category_{{ category }}" value="1"/> + {% endfor %} + <input type="hidden" name="pageno" value="{{ pageno }}" /> + <input type="submit" value="{{ output_type }}" /> + </div> + </form> + {% endfor %} + </div> + </div> + + {% if suggestions %} + <div id="suggestions"><span>{{ _('Suggestions') }}</span> + {% for suggestion in suggestions %} + <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}"> + <input type="hidden" name="q" value="{{ suggestion }}"> + <input type="submit" value="{{ suggestion }}" /> + </form> + {% endfor %} + </div> + {% endif %} + + {% for result in results %} + {% if result['template'] %} + {% include 'default/result_templates/'+result['template'] %} + {% else %} + {% include 'default/result_templates/default.html' %} + {% endif %} + {% endfor %} + + {% if paging %} + <div id="pagination"> + {% if pageno > 1 %} + <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}"> + <div class="left"> + <input type="hidden" name="q" value="{{ q }}" /> + {% for category in selected_categories %} + <input type="hidden" name="category_{{ category }}" value="1"/> + {% endfor %} + <input type="hidden" name="pageno" value="{{ pageno-1 }}" /> + <input type="submit" value="<< {{ _('previous page') }}" /> + </div> + </form> + {% endif %} + <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}"> + <div class="left"> + {% for category in selected_categories %} + <input type="hidden" name="category_{{ category }}" value="1"/> + {% endfor %} + <input type="hidden" name="q" value="{{ q }}" /> + <input type="hidden" name="pageno" value="{{ pageno+1 }}" /> + <input type="submit" value="{{ _('next page') }} >>" /> + </div> + </form> + </div> + {% endif %} +</div> +{% endblock %} diff --git a/searx/templates/default/search.html b/searx/templates/default/search.html @@ -0,0 +1,7 @@ +<form method="{{ method or 'POST' }}" action="{{ url_for('index') }}" id="search_form"> + <div id="search_wrapper"> + <input type="text" placeholder="{{ _('Search for...') }}" id="q" class="q" name="q" tabindex="1" autocomplete="off" {% if q %}value="{{ q }}"{% endif %}/> + <input type="submit" value="search" id="search_submit" /> + </div> + {% include 'default/categories.html' %} +</form> diff --git a/searx/templates/default/stats.html b/searx/templates/default/stats.html @@ -0,0 +1,22 @@ +{% extends "default/base.html" %} +{% block head %} {% endblock %} +{% block content %} +<h2>{{ _('Engine stats') }}</h2> + +{% for stat_name,stat_category in stats %} +<div class="left"> + <table> + <tr colspan="3"> + <th>{{ stat_name }}</th> + </tr> + {% for engine in stat_category %} + <tr> + <td>{{ engine.name }}</td> + <td>{{ '%.02f'|format(engine.avg) }}</td> + <td class="percentage"><div style="width: {{ engine.percentage }}%">&nbsp;</div></td> + </tr> + {% endfor %} + </table> +</div> +{% endfor %} +{% endblock %} diff --git a/searx/templates/index.html b/searx/templates/index.html @@ -1,11 +0,0 @@ -{% extends "base.html" %} -{% block content %} -<div class="center"> - <div class="title"><h1>searx</h1></div> - {% include '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 %} diff --git a/searx/templates/preferences.html b/searx/templates/preferences.html @@ -1,91 +0,0 @@ -{% extends "base.html" %} -{% block head %} {% endblock %} -{% block content %} -<div class="row"> - <h2>{{ _('Preferences') }}</h2> - - <form method="post" action="{{ url_for('preferences') }}" id="search_form"> - <fieldset> - <legend>{{ _('Default categories') }}</legend> - <p> - {% include 'categories.html' %} - </p> - </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> - </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> - </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> - </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> - </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 %} - <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> - </tr> - {% endif %} - {% endfor %} - {% endfor %} - </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.") }} - </p> - - <input type="submit" value="{{ _('save') }}" /> - <div class="right preferences_back"><a href="{{ url_for('index') }}">{{ _('back') }}</a></div> - </form> -</div> -{% endblock %} diff --git a/searx/templates/result_templates/default.html b/searx/templates/result_templates/default.html @@ -1,13 +0,0 @@ -<div class="result {{ result.class }}"> - - {% if result['favicon'] %} - <img width="14" height="14" class="favicon" src="static/img/icon_{{result['favicon']}}.ico" /> - {% 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> diff --git a/searx/templates/result_templates/videos.html b/searx/templates/result_templates/videos.html @@ -1,12 +0,0 @@ -<div class="result"> - {% if result['favicon'] %} - <img width="14" height="14" class="favicon" src="static/img/icon_{{result['favicon']}}.ico" /> - {% endif %} - - <p> - <h3 class="result_title"><a href="{{ result.url }}">{{ result.title|safe }}</a></h3> - {% if result.publishedDate %}<p class="published_date">{{ result.publishedDate }}</p>{% endif %} - <a href="{{ result.url }}"><img width="400px" src="{{ result.thumbnail }}" title={{ result.title }} alt=" {{ result.title }}"/></a> - <p class="url">{{ result.url }}</p> - </p> -</div> diff --git a/searx/templates/results.html b/searx/templates/results.html @@ -1,79 +0,0 @@ -{% extends "base.html" %} -{% block title %}{{ q }} - {% endblock %} -{% block content %} -<div class="right"><a href="{{ url_for('preferences') }}" id="preferences"><span>preferences</span></a></div> -<div class="small search center"> - {% include 'search.html' %} -</div> -<div id="results"> - <div id="sidebar"> - - <div id="search_url"> - {{ _('Search URL') }}: - <input type="text" value="{{ base_url }}?q={{ q|urlencode }}&pageno={{ pageno }}{% if selected_categories %}&category_{{ selected_categories|join("&category_") }}{% endif %}" readonly="" /> - </div> - <div id="apis"> - {{ _('Download results') }} - {% for output_type in ('csv', 'json', 'rss') %} - <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}"> - <div class="left"> - <input type="hidden" name="q" value="{{ q }}" /> - <input type="hidden" name="format" value="{{ output_type }}" /> - {% for category in selected_categories %} - <input type="hidden" name="category_{{ category }}" value="1"/> - {% endfor %} - <input type="hidden" name="pageno" value="{{ pageno }}" /> - <input type="submit" value="{{ output_type }}" /> - </div> - </form> - {% endfor %} - </div> - </div> - - {% if suggestions %} - <div id="suggestions"><span>{{ _('Suggestions') }}</span> - {% for suggestion in suggestions %} - <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}"> - <input type="hidden" name="q" value="{{ suggestion }}"> - <input type="submit" value="{{ suggestion }}" /> - </form> - {% endfor %} - </div> - {% endif %} - - {% for result in results %} - {% if result['template'] %} - {% include 'result_templates/'+result['template'] %} - {% else %} - {% include 'result_templates/default.html' %} - {% endif %} - {% endfor %} - - {% if paging %} - <div id="pagination"> - {% if pageno > 1 %} - <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}"> - <div class="left"> - <input type="hidden" name="q" value="{{ q }}" /> - {% for category in selected_categories %} - <input type="hidden" name="category_{{ category }}" value="1"/> - {% endfor %} - <input type="hidden" name="pageno" value="{{ pageno-1 }}" /> - <input type="submit" value="<< {{ _('previous page') }}" /> - </div> - </form> - {% endif %} - <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}"> - <div class="left"> - {% for category in selected_categories %} - <input type="hidden" name="category_{{ category }}" value="1"/> - {% endfor %} - <input type="hidden" name="q" value="{{ q }}" /> - <input type="hidden" name="pageno" value="{{ pageno+1 }}" /> - <input type="submit" value="{{ _('next page') }} >>" /> - </div> - </form> - </div> - {% endif %} -</div> -{% endblock %} diff --git a/searx/templates/search.html b/searx/templates/search.html @@ -1,7 +0,0 @@ -<form method="{{ method or 'POST' }}" action="{{ url_for('index') }}" id="search_form"> - <div id="search_wrapper"> - <input type="text" placeholder="{{ _('Search for...') }}" id="q" class="q" name="q" tabindex="1" autocomplete="off" {% if q %}value="{{ q }}"{% endif %}/> - <input type="submit" value="search" id="search_submit" /> - </div> - {% include 'categories.html' %} -</form> diff --git a/searx/templates/stats.html b/searx/templates/stats.html @@ -1,22 +0,0 @@ -{% extends "base.html" %} -{% block head %} {% endblock %} -{% block content %} -<h2>{{ _('Engine stats') }}</h2> - -{% for stat_name,stat_category in stats %} -<div class="left"> - <table> - <tr colspan="3"> - <th>{{ stat_name }}</th> - </tr> - {% for engine in stat_category %} - <tr> - <td>{{ engine.name }}</td> - <td>{{ '%.02f'|format(engine.avg) }}</td> - <td class="percentage"><div style="width: {{ engine.percentage }}%">&nbsp;</div></td> - </tr> - {% endfor %} - </table> -</div> -{% endfor %} -{% endblock %} diff --git a/searx/utils.py b/searx/utils.py @@ -1,10 +1,12 @@ -from HTMLParser import HTMLParser #import htmlentitydefs -import csv from codecs import getincrementalencoder +from HTMLParser import HTMLParser +from random import choice + import cStringIO +import csv +import os import re -from random import choice ua_versions = ('26.0', '27.0', '28.0') ua_os = ('Windows NT 6.3; WOW64', @@ -110,3 +112,17 @@ class UnicodeWriter: def writerows(self, rows): for row in rows: self.writerow(row) + + +def get_themes(root): + """Returns available themes list.""" + + static_path = os.path.join(root, 'static') + static_names = set(os.listdir(static_path)) + templates_path = os.path.join(root, 'templates') + templates_names = set(os.listdir(templates_path)) + + themes = [] + for name in static_names.intersection(templates_names): + themes += [name] + return static_path, templates_path, themes diff --git a/searx/webapp.py b/searx/webapp.py @@ -38,16 +38,23 @@ from searx.engines import ( search as do_search, categories, engines, get_engines_stats, engine_shortcuts ) -from searx.utils import UnicodeWriter, highlight_content, html_to_text +from searx.utils import ( + UnicodeWriter, highlight_content, html_to_text, get_themes +) from searx.languages import language_codes from searx.search import Search from searx.autocomplete import backends as autocomplete_backends +static_path, templates_path, themes = get_themes(settings['themes_path'] if \ + settings.get('themes_path', None) else searx_dir) +default_theme = settings['default_theme'] if \ + settings.get('default_theme', None) else 'default' + app = Flask( __name__, - static_folder=os.path.join(searx_dir, 'static'), - template_folder=os.path.join(searx_dir, 'templates') + static_folder=static_path, + template_folder=templates_path ) app.secret_key = settings['server']['secret_key'] @@ -90,7 +97,30 @@ def get_base_url(): return hostname -def render(template_name, **kwargs): +def get_current_theme_name(override=None): + """Returns theme name. + + Checks in this order: + 1. override + 2. cookies + 3. settings""" + + if override and override in themes: + return override + theme_name = request.cookies.get('theme', default_theme) + if theme_name not in themes: + theme_name = default_theme + return theme_name + + +def url_for_theme(endpoint, override_theme=None, **values): + if endpoint == 'static' and values.get('filename', None): + theme_name = get_current_theme_name(override=override_theme) + values['filename'] = "{}/{}".format(theme_name, values['filename']) + return url_for(endpoint, **values) + + +def render(template_name, override_theme=None, **kwargs): blocked_engines = request.cookies.get('blocked_engines', '').split(',') autocomplete = request.cookies.get('autocomplete') @@ -125,7 +155,13 @@ def render(template_name, **kwargs): kwargs['method'] = request.cookies.get('method', 'POST') - return render_template(template_name, **kwargs) + # override url_for function in templates + kwargs['url_for'] = url_for_theme + + kwargs['theme'] = get_current_theme_name(override=override_theme) + + return render_template( + '{}/{}'.format(kwargs['theme'], template_name), **kwargs) @app.route('/search', methods=['GET', 'POST']) @@ -232,7 +268,8 @@ def index(): paging=search.paging, pageno=search.pageno, base_url=get_base_url(), - suggestions=search.suggestions + suggestions=search.suggestions, + theme=get_current_theme_name() ) @@ -290,7 +327,7 @@ def preferences(): if request.method == 'GET': blocked_engines = request.cookies.get('blocked_engines', '').split(',') - else: + else: # on save selected_categories = [] locale = None autocomplete = '' @@ -315,6 +352,8 @@ def preferences(): engine_name = pd_name.replace('engine_', '', 1) if engine_name in engines: blocked_engines.append(engine_name) + elif pd_name == 'theme': + theme = pd if pd in themes else default_theme resp = make_response(redirect(url_for('index'))) @@ -352,6 +391,9 @@ def preferences(): resp.set_cookie('method', method, max_age=cookie_max_age) + resp.set_cookie( + 'theme', theme, max_age=cookie_max_age) + return resp return render('preferences.html', locales=settings['locales'], @@ -361,7 +403,9 @@ def preferences(): categs=categories.items(), blocked_engines=blocked_engines, autocomplete_backends=autocomplete_backends, - shortcuts={y: x for x, y in engine_shortcuts.items()}) + shortcuts={y: x for x, y in engine_shortcuts.items()}, + themes=themes, + theme=get_current_theme_name()) @app.route('/stats', methods=['GET']) @@ -404,7 +448,10 @@ def opensearch(): @app.route('/favicon.ico') def favicon(): - return send_from_directory(os.path.join(app.root_path, 'static/img'), + return send_from_directory(os.path.join(app.root_path, + 'static', + get_current_theme_name(), + 'img'), 'favicon.png', mimetype='image/vnd.microsoft.icon')