diff --git a/Makefile b/Makefile index fbc1c485..2ef352eb 100644 --- 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 index eac7593c..69f22f5d 100644 --- 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 similarity index 100% rename from searx/static/css/style.css rename to searx/static/default/css/style.css diff --git a/searx/static/img/favicon.png b/searx/static/default/img/favicon.png similarity index 100% rename from searx/static/img/favicon.png rename to searx/static/default/img/favicon.png diff --git a/searx/static/img/github_ribbon.png b/searx/static/default/img/github_ribbon.png similarity index 100% rename from searx/static/img/github_ribbon.png rename to searx/static/default/img/github_ribbon.png diff --git a/searx/static/img/icon_github.ico b/searx/static/default/img/icon_github.ico similarity index 100% rename from searx/static/img/icon_github.ico rename to searx/static/default/img/icon_github.ico diff --git a/searx/static/img/icon_soundcloud.ico b/searx/static/default/img/icon_soundcloud.ico similarity index 100% rename from searx/static/img/icon_soundcloud.ico rename to searx/static/default/img/icon_soundcloud.ico diff --git a/searx/static/img/icon_stackoverflow.ico b/searx/static/default/img/icon_stackoverflow.ico similarity index 100% rename from searx/static/img/icon_stackoverflow.ico rename to searx/static/default/img/icon_stackoverflow.ico diff --git a/searx/static/img/icon_twitter.ico b/searx/static/default/img/icon_twitter.ico similarity index 100% rename from searx/static/img/icon_twitter.ico rename to searx/static/default/img/icon_twitter.ico diff --git a/searx/static/img/icon_vimeo.ico b/searx/static/default/img/icon_vimeo.ico similarity index 100% rename from searx/static/img/icon_vimeo.ico rename to searx/static/default/img/icon_vimeo.ico diff --git a/searx/static/img/icon_wikipedia.ico b/searx/static/default/img/icon_wikipedia.ico similarity index 100% rename from searx/static/img/icon_wikipedia.ico rename to searx/static/default/img/icon_wikipedia.ico diff --git a/searx/static/img/icon_youtube.ico b/searx/static/default/img/icon_youtube.ico similarity index 100% rename from searx/static/img/icon_youtube.ico rename to searx/static/default/img/icon_youtube.ico diff --git a/searx/static/img/preference-icon.png b/searx/static/default/img/preference-icon.png similarity index 100% rename from searx/static/img/preference-icon.png rename to searx/static/default/img/preference-icon.png diff --git a/searx/static/img/search-icon.png b/searx/static/default/img/search-icon.png similarity index 100% rename from searx/static/img/search-icon.png rename to searx/static/default/img/search-icon.png diff --git a/searx/static/img/searx.png b/searx/static/default/img/searx.png similarity index 100% rename from searx/static/img/searx.png rename to searx/static/default/img/searx.png diff --git a/searx/static/img/searx_logo.svg b/searx/static/default/img/searx_logo.svg similarity index 100% rename from searx/static/img/searx_logo.svg rename to 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 similarity index 100% rename from searx/static/js/mootools-autocompleter-1.1.2-min.js rename to 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 similarity index 100% rename from searx/static/js/mootools-core-1.4.5-min.js rename to 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 similarity index 100% rename from searx/static/js/searx.js rename to searx/static/default/js/searx.js diff --git a/searx/static/less/autocompleter.less b/searx/static/default/less/autocompleter.less similarity index 100% rename from searx/static/less/autocompleter.less rename to searx/static/default/less/autocompleter.less diff --git a/searx/static/less/definitions.less b/searx/static/default/less/definitions.less similarity index 100% rename from searx/static/less/definitions.less rename to searx/static/default/less/definitions.less diff --git a/searx/static/less/mixins.less b/searx/static/default/less/mixins.less similarity index 100% rename from searx/static/less/mixins.less rename to searx/static/default/less/mixins.less diff --git a/searx/static/less/search.less b/searx/static/default/less/search.less similarity index 100% rename from searx/static/less/search.less rename to searx/static/default/less/search.less diff --git a/searx/static/less/style.less b/searx/static/default/less/style.less similarity index 100% rename from searx/static/less/style.less rename to searx/static/default/less/style.less diff --git a/searx/templates/about.html b/searx/templates/default/about.html similarity index 97% rename from searx/templates/about.html rename to searx/templates/default/about.html index 0ddf1225..19aba190 100644 --- a/searx/templates/about.html +++ b/searx/templates/default/about.html @@ -1,6 +1,6 @@ -{% extends 'base.html' %} +{% extends 'default/base.html' %} {% block content %} -{% include 'github_ribbon.html' %} +{% include 'default/github_ribbon.html' %}

About searx

diff --git a/searx/templates/base.html b/searx/templates/default/base.html similarity index 100% rename from searx/templates/base.html rename to searx/templates/default/base.html diff --git a/searx/templates/categories.html b/searx/templates/default/categories.html similarity index 100% rename from searx/templates/categories.html rename to searx/templates/default/categories.html diff --git a/searx/templates/github_ribbon.html b/searx/templates/default/github_ribbon.html similarity index 100% rename from searx/templates/github_ribbon.html rename to searx/templates/default/github_ribbon.html diff --git a/searx/templates/index.html b/searx/templates/default/index.html similarity index 80% rename from searx/templates/index.html rename to searx/templates/default/index.html index 57b67ef0..43ba8837 100644 --- a/searx/templates/index.html +++ b/searx/templates/default/index.html @@ -1,8 +1,8 @@ -{% extends "base.html" %} +{% extends "default/base.html" %} {% block content %}

searx

- {% include 'search.html' %} + {% include 'default/search.html' %}

{{ _('about') }} {{ _('preferences') }} diff --git a/searx/templates/opensearch.xml b/searx/templates/default/opensearch.xml similarity index 100% rename from searx/templates/opensearch.xml rename to searx/templates/default/opensearch.xml diff --git a/searx/templates/opensearch_response_rss.xml b/searx/templates/default/opensearch_response_rss.xml similarity index 100% rename from searx/templates/opensearch_response_rss.xml rename to searx/templates/default/opensearch_response_rss.xml diff --git a/searx/templates/preferences.html b/searx/templates/default/preferences.html similarity index 90% rename from searx/templates/preferences.html rename to searx/templates/default/preferences.html index eeb86577..7d35de7c 100644 --- a/searx/templates/preferences.html +++ b/searx/templates/default/preferences.html @@ -1,4 +1,4 @@ -{% extends "base.html" %} +{% extends "default/base.html" %} {% block head %} {% endblock %} {% block content %}

@@ -8,7 +8,7 @@
{{ _('Default categories') }}

- {% include 'categories.html' %} + {% include 'default/categories.html' %}

@@ -52,6 +52,16 @@

+
+ {{ _('Themes') }} +

+ +

+
{{ _('Currently used search engines') }} diff --git a/searx/templates/result_templates/default.html b/searx/templates/default/result_templates/default.html similarity index 80% rename from searx/templates/result_templates/default.html rename to searx/templates/default/result_templates/default.html index e0711b76..734f9066 100644 --- a/searx/templates/result_templates/default.html +++ b/searx/templates/default/result_templates/default.html @@ -1,7 +1,7 @@
{% if result['favicon'] %} - + {% endif %}
diff --git a/searx/templates/result_templates/images.html b/searx/templates/default/result_templates/images.html similarity index 100% rename from searx/templates/result_templates/images.html rename to searx/templates/default/result_templates/images.html diff --git a/searx/templates/result_templates/torrent.html b/searx/templates/default/result_templates/torrent.html similarity index 100% rename from searx/templates/result_templates/torrent.html rename to searx/templates/default/result_templates/torrent.html diff --git a/searx/templates/result_templates/videos.html b/searx/templates/default/result_templates/videos.html similarity index 80% rename from searx/templates/result_templates/videos.html rename to searx/templates/default/result_templates/videos.html index ab869a6e..8ceb0b18 100644 --- a/searx/templates/result_templates/videos.html +++ b/searx/templates/default/result_templates/videos.html @@ -1,6 +1,6 @@
{% if result['favicon'] %} - + {% endif %}

diff --git a/searx/templates/results.html b/searx/templates/default/results.html similarity index 93% rename from searx/templates/results.html rename to searx/templates/default/results.html index 608cfb20..d0b53b48 100644 --- a/searx/templates/results.html +++ b/searx/templates/default/results.html @@ -1,9 +1,9 @@ -{% extends "base.html" %} +{% extends "default/base.html" %} {% block title %}{{ q }} - {% endblock %} {% block content %}

- {% include 'categories.html' %} + {% include 'default/categories.html' %} diff --git a/searx/templates/stats.html b/searx/templates/default/stats.html similarity index 94% rename from searx/templates/stats.html rename to searx/templates/default/stats.html index cb5757b3..70fe98ac 100644 --- a/searx/templates/stats.html +++ b/searx/templates/default/stats.html @@ -1,4 +1,4 @@ -{% extends "base.html" %} +{% extends "default/base.html" %} {% block head %} {% endblock %} {% block content %}

{{ _('Engine stats') }}

diff --git a/searx/utils.py b/searx/utils.py index b8c7a8c6..a9ece355 100644 --- a/searx/utils.py +++ b/searx/utils.py @@ -1,11 +1,13 @@ -from HTMLParser import HTMLParser #import htmlentitydefs -import csv from codecs import getincrementalencoder -import cStringIO -import re +from HTMLParser import HTMLParser from random import choice +import cStringIO +import csv +import os +import re + ua_versions = ('26.0', '27.0', '28.0') ua_os = ('Windows NT 6.3; WOW64', 'X11; Linux x86_64', @@ -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 index 89d288e7..158dc35a 100644 --- 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')