mirror of
https://github.com/searxng/searxng
synced 2024-01-01 19:24:07 +01:00
[feat] allow customization of logo and favicon
also removed searxng-wordmark from templates directory and build files, because it is no longer used anywhere
This commit is contained in:
parent
0245e82bd2
commit
0c202474c4
15 changed files with 92 additions and 12 deletions
|
@ -173,4 +173,5 @@ features or generally made searx better:
|
||||||
- Austin Olacsi `<https://github.com/Austin-Olacsi>`
|
- Austin Olacsi `<https://github.com/Austin-Olacsi>`
|
||||||
- @micsthepick
|
- @micsthepick
|
||||||
- Daniel Kukula `<https://github.com/dkuku>`
|
- Daniel Kukula `<https://github.com/dkuku>`
|
||||||
- Patrick Evans `https://github.com/holysoles`
|
- Patrick Evans `https://github.com/holysoles`
|
||||||
|
- shreven `<https://shreven.org>`_ B8B56F6FC0EADCA5B6177BC5F599020F48EE6F97
|
||||||
|
|
|
@ -11,6 +11,10 @@
|
||||||
docs_url: https://docs.searxng.org
|
docs_url: https://docs.searxng.org
|
||||||
public_instances: https://searx.space
|
public_instances: https://searx.space
|
||||||
wiki_url: https://github.com/searxng/searxng/wiki
|
wiki_url: https://github.com/searxng/searxng/wiki
|
||||||
|
custom_files:
|
||||||
|
logo: /path/to/file.png
|
||||||
|
favicon_png: /path/to/file.png
|
||||||
|
favicon_svg: /path/to/file.svg
|
||||||
|
|
||||||
``issue_url`` :
|
``issue_url`` :
|
||||||
If you host your own issue tracker change this URL.
|
If you host your own issue tracker change this URL.
|
||||||
|
@ -23,3 +27,12 @@
|
||||||
|
|
||||||
``wiki_url`` :
|
``wiki_url`` :
|
||||||
Link to your wiki (or ``false``)
|
Link to your wiki (or ``false``)
|
||||||
|
|
||||||
|
``custom_files.logo`` :
|
||||||
|
Filepath to a custom logo. Be sure it has the right file extension, as that's used to determine the mimetype.
|
||||||
|
|
||||||
|
``custom_files.favicon_png`` :
|
||||||
|
Filepath to a custom PNG favicon.
|
||||||
|
|
||||||
|
``custom_files.favicon_svg`` :
|
||||||
|
Filepath to a custom SVG favicon. When using, be sure to also set ``custom_files.favicon_png``, as some browsers still don't support SVG favicons.
|
||||||
|
|
|
@ -29,6 +29,12 @@ brand:
|
||||||
# links:
|
# links:
|
||||||
# Uptime: https://uptime.searxng.org/history/darmarit-org
|
# Uptime: https://uptime.searxng.org/history/darmarit-org
|
||||||
# About: "https://searxng.org"
|
# About: "https://searxng.org"
|
||||||
|
# custom_files:
|
||||||
|
# # If using custom logo, be sure to set the right file extension as it's used to determine the mimetype.
|
||||||
|
# logo: /path/to/file.png
|
||||||
|
# # For custom favicons, you must include a PNG version, as some browsers still don't support SVG favicons.
|
||||||
|
# favicon_png: /path/to/file.png
|
||||||
|
# favicon_svg: /path/to/file.svg
|
||||||
|
|
||||||
search:
|
search:
|
||||||
# Filter results. 0: None, 1: Moderate, 2: Strict
|
# Filter results. 0: None, 1: Moderate, 2: Strict
|
||||||
|
|
|
@ -152,6 +152,7 @@ SCHEMA = {
|
||||||
'public_instances': SettingsValue((False, str), 'https://searx.space'),
|
'public_instances': SettingsValue((False, str), 'https://searx.space'),
|
||||||
'wiki_url': SettingsValue(str, 'https://github.com/searxng/searxng/wiki'),
|
'wiki_url': SettingsValue(str, 'https://github.com/searxng/searxng/wiki'),
|
||||||
'custom': SettingsValue(dict, {'links': {}}),
|
'custom': SettingsValue(dict, {'links': {}}),
|
||||||
|
'custom_files': SettingsValue(dict, {}),
|
||||||
},
|
},
|
||||||
'search': {
|
'search': {
|
||||||
'safe_search': SettingsValue((0, 1, 2), 0),
|
'safe_search': SettingsValue((0, 1, 2), 0),
|
||||||
|
|
|
@ -151,7 +151,6 @@ module.exports = function (grunt) {
|
||||||
svgo: ['--config', 'svg4web.svgo.js']
|
svgo: ['--config', 'svg4web.svgo.js']
|
||||||
},
|
},
|
||||||
files: {
|
files: {
|
||||||
'<%= _templates %>/simple/searxng-wordmark.min.svg': '<%= _brand %>/searxng-wordmark.svg',
|
|
||||||
'img/searxng.svg': '<%= _brand %>/searxng.svg',
|
'img/searxng.svg': '<%= _brand %>/searxng.svg',
|
||||||
'img/img_load_error.svg': '<%= _brand %>/img_load_error.svg'
|
'img/img_load_error.svg': '<%= _brand %>/img_load_error.svg'
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,11 @@
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
background: url('../img/searxng.png') no-repeat;
|
&.custom_logo {
|
||||||
|
background-image: url('../../../../custom/logo');
|
||||||
|
}
|
||||||
|
background-image: url('../img/searxng.png');
|
||||||
|
background-repeat: no-repeat;
|
||||||
min-height: 4rem;
|
min-height: 4rem;
|
||||||
margin: 4rem auto;
|
margin: 4rem auto;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
|
|
|
@ -27,9 +27,11 @@
|
||||||
{% block head %}
|
{% block head %}
|
||||||
<link title="{{ instance_name }}" type="application/opensearchdescription+xml" rel="search" href="{{ opensearch_url }}">
|
<link title="{{ instance_name }}" type="application/opensearchdescription+xml" rel="search" href="{{ opensearch_url }}">
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
<link rel="icon" href="{{ url_for('static', filename='img/favicon.png') }}" sizes="any">
|
<link rel="icon" href="{{ url_for('custom', custom_file='favicon_png', filename='img/favicon.png') }}" sizes="any">
|
||||||
<link rel="icon" href="{{ url_for('static', filename='img/favicon.svg') }}" type="image/svg+xml">
|
<link rel="apple-touch-icon" href="{{ url_for('custom', custom_file='favicon_png', filename='img/favicon.png') }}">
|
||||||
<link rel="apple-touch-icon" href="{{ url_for('static', filename='img/favicon.png') }}">
|
{% if not get_setting('brand.custom_files.favicon_png', false) or get_setting('brand.custom_files.favicon_svg', false) %}
|
||||||
|
<link rel="icon" href="{{ url_for('custom', custom_file='favicon_svg', filename='img/favicon.svg') }}" type="image/svg+xml">
|
||||||
|
{% endif %}
|
||||||
</head>
|
</head>
|
||||||
<body class="{{ endpoint }}_endpoint" >
|
<body class="{{ endpoint }}_endpoint" >
|
||||||
<main id="main_{{ self._TemplateReference__context.name|replace("simple/", "")|replace(".html", "") }}" class="{{body_class}}">
|
<main id="main_{{ self._TemplateReference__context.name|replace("simple/", "")|replace(".html", "") }}" class="{{body_class}}">
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
{% from 'simple/icons.html' import icon_big %}
|
{% from 'simple/icons.html' import icon_big %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="index">
|
<div class="index">
|
||||||
<div class="title"><h1>SearXNG</h1></div>
|
<div class="title{% if get_setting('brand.custom_files.logo', false) %} custom_logo{% endif %}"><h1>SearXNG</h1></div>
|
||||||
{% include 'simple/simple_search.html' %}
|
{% include 'simple/simple_search.html' %}
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<LongName>SearXNG metasearch</LongName>
|
<LongName>SearXNG metasearch</LongName>
|
||||||
<Description>SearXNG is a metasearch engine that respects your privacy.</Description>
|
<Description>SearXNG is a metasearch engine that respects your privacy.</Description>
|
||||||
<InputEncoding>UTF-8</InputEncoding>
|
<InputEncoding>UTF-8</InputEncoding>
|
||||||
<Image type="image/png">{{ url_for('static', filename='img/favicon.png', _external=True) }}</Image>
|
<Image type="image/png">{{ url_for('custom', custom_file='favicon_png', filename='img/favicon.png', _external=True) }}</Image>
|
||||||
{% if opensearch_method == 'GET' %}
|
{% if opensearch_method == 'GET' %}
|
||||||
<Url rel="results" type="text/html" method="{{ opensearch_method }}" template="{{ url_for('search', _external=True) }}?q={searchTerms}"/>
|
<Url rel="results" type="text/html" method="{{ opensearch_method }}" template="{{ url_for('search', _external=True) }}?q={searchTerms}"/>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
|
@ -2,6 +2,6 @@
|
||||||
{%- extends "simple/base.html" -%}
|
{%- extends "simple/base.html" -%}
|
||||||
{%- block header -%}
|
{%- block header -%}
|
||||||
<a href="{{ url_for('index') }}">{{- '' -}}
|
<a href="{{ url_for('index') }}">{{- '' -}}
|
||||||
<img class="logo" src="{{ url_for('static', filename='img/searxng.png') }}" alt="SearXNG">{{- '' -}}
|
<img class="logo" src="{{ url_for('custom', custom_file='logo', filename='img/searxng.png') }}" alt="SearXNG">{{- '' -}}
|
||||||
</a>{{- '' -}}
|
</a>{{- '' -}}
|
||||||
{%- endblock -%}
|
{%- endblock -%}
|
||||||
|
|
|
@ -2,7 +2,12 @@
|
||||||
<div id="search_header">
|
<div id="search_header">
|
||||||
<a id="search_logo" href="{{ url_for('index') }}" tabindex="0" title="{{ _('Display the front page') }}">
|
<a id="search_logo" href="{{ url_for('index') }}" tabindex="0" title="{{ _('Display the front page') }}">
|
||||||
<span hidden>SearXNG</span>
|
<span hidden>SearXNG</span>
|
||||||
{% include 'simple/searxng-wordmark.min.svg' without context %}
|
<img width="23px" height="23px" src="
|
||||||
|
{%- if not get_setting('brand.custom_files.favicon_svg', false) -%}
|
||||||
|
{{ url_for('custom', custom_file='favicon_png', filename='img/favicon.svg') }}
|
||||||
|
{%- else -%} {{ url_for('custom', custom_file='favicon_svg', filename='img/favicon.svg') }}
|
||||||
|
{%- endif -%}
|
||||||
|
"></img>
|
||||||
</a>
|
</a>
|
||||||
<div id="search_view">
|
<div id="search_view">
|
||||||
<div class="search_box">
|
<div class="search_box">
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="92mm" height="92mm" viewBox="0 0 92 92"><g transform="translate(-40.921 -17.417)"><circle cx="75.921" cy="53.903" r="30" fill="none" fill-opacity="1" stroke="#3050ff" stroke-width="10" stroke-miterlimit="4" stroke-dasharray="none" stroke-opacity="1"/><path d="M67.515 37.915a18 18 0 0 1 21.051 3.313 18 18 0 0 1 3.138 21.078" fill="none" fill-opacity="1" stroke="#3050ff" stroke-width="5" stroke-miterlimit="4" stroke-dasharray="none" stroke-opacity="1"/><rect width="18.846" height="39.963" x="3.706" y="122.09" ry="0" transform="rotate(-46.235)" opacity="1" fill="#3050ff" fill-opacity="1" stroke="none" stroke-width="8" stroke-miterlimit="4" stroke-dasharray="none" stroke-opacity="1"/></g></svg>
|
|
Before Width: | Height: | Size: 746 B |
|
@ -37,6 +37,7 @@ from flask import (
|
||||||
make_response,
|
make_response,
|
||||||
redirect,
|
redirect,
|
||||||
send_from_directory,
|
send_from_directory,
|
||||||
|
send_file,
|
||||||
)
|
)
|
||||||
from flask.wrappers import Response
|
from flask.wrappers import Response
|
||||||
from flask.json import jsonify
|
from flask.json import jsonify
|
||||||
|
@ -74,6 +75,7 @@ from searx import webutils
|
||||||
from searx.webutils import (
|
from searx.webutils import (
|
||||||
highlight_content,
|
highlight_content,
|
||||||
get_static_files,
|
get_static_files,
|
||||||
|
get_custom_files,
|
||||||
get_result_templates,
|
get_result_templates,
|
||||||
get_themes,
|
get_themes,
|
||||||
exception_classname_to_text,
|
exception_classname_to_text,
|
||||||
|
@ -132,6 +134,7 @@ if not searx_debug and settings['server']['secret_key'] == 'ultrasecretkey':
|
||||||
# about static
|
# about static
|
||||||
logger.debug('static directory is %s', settings['ui']['static_path'])
|
logger.debug('static directory is %s', settings['ui']['static_path'])
|
||||||
static_files = get_static_files(settings['ui']['static_path'])
|
static_files = get_static_files(settings['ui']['static_path'])
|
||||||
|
custom_files = get_custom_files()
|
||||||
|
|
||||||
# about templates
|
# about templates
|
||||||
logger.debug('templates directory is %s', settings['ui']['templates_path'])
|
logger.debug('templates directory is %s', settings['ui']['templates_path'])
|
||||||
|
@ -256,6 +259,15 @@ def get_result_template(theme_name: str, template_name: str):
|
||||||
|
|
||||||
def custom_url_for(endpoint: str, **values):
|
def custom_url_for(endpoint: str, **values):
|
||||||
suffix = ""
|
suffix = ""
|
||||||
|
if endpoint == 'custom' and values.get('custom_file'):
|
||||||
|
if values['custom_file'] in custom_files:
|
||||||
|
values.pop('filename')
|
||||||
|
if get_setting('ui.static_use_hash'):
|
||||||
|
suffix = "?" + custom_files[values['custom_file']]['hash']
|
||||||
|
else:
|
||||||
|
# if there's no custom file defined in settings.yml, then use the default file
|
||||||
|
values.pop('custom_file')
|
||||||
|
endpoint = 'static'
|
||||||
if endpoint == 'static' and values.get('filename'):
|
if endpoint == 'static' and values.get('filename'):
|
||||||
file_hash = static_files.get(values['filename'])
|
file_hash = static_files.get(values['filename'])
|
||||||
if not file_hash:
|
if not file_hash:
|
||||||
|
@ -1279,8 +1291,25 @@ def opensearch():
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/custom/<path:custom_file>')
|
||||||
|
def custom(custom_file):
|
||||||
|
if custom_file in custom_files:
|
||||||
|
filepath = custom_files[custom_file]['path']
|
||||||
|
if os.path.isfile(filepath):
|
||||||
|
if 'mimetype' in custom_files[custom_file]:
|
||||||
|
return send_file(filepath, mimetype=custom_files[custom_file]['mimetype'])
|
||||||
|
return send_file(filepath)
|
||||||
|
logger.warning('%s does not exist or is not a file', filepath)
|
||||||
|
return flask.abort(404)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/favicon.ico')
|
@app.route('/favicon.ico')
|
||||||
def favicon():
|
def favicon():
|
||||||
|
if 'favicon_png' in custom_files:
|
||||||
|
filepath = custom_files['favicon_png']['path']
|
||||||
|
if os.path.isfile(filepath):
|
||||||
|
return send_file(filepath, mimetype='image/png')
|
||||||
|
logger.warning('%s does not exist or is not a file', filepath)
|
||||||
theme = request.preferences.get_value("theme")
|
theme = request.preferences.get_value("theme")
|
||||||
return send_from_directory(
|
return send_from_directory(
|
||||||
os.path.join(app.root_path, settings['ui']['static_path'], 'themes', theme, 'img'), # pyright: ignore
|
os.path.join(app.root_path, settings['ui']['static_path'], 'themes', theme, 'img'), # pyright: ignore
|
||||||
|
|
|
@ -204,6 +204,28 @@ def get_static_files(static_path: str) -> Dict[str, str]:
|
||||||
return static_files
|
return static_files
|
||||||
|
|
||||||
|
|
||||||
|
def get_custom_files() -> Dict[str, dict]:
|
||||||
|
custom_files: Dict[str, dict] = {}
|
||||||
|
|
||||||
|
for option in settings['brand']['custom_files']:
|
||||||
|
filepath = settings['brand']['custom_files'][option]
|
||||||
|
if os.path.isfile(filepath):
|
||||||
|
custom_files.setdefault(option, {})
|
||||||
|
custom_files[option]['path'] = filepath
|
||||||
|
custom_files[option]['hash'] = get_hash_for_file(pathlib.Path(filepath))
|
||||||
|
if option == 'favicon_png':
|
||||||
|
custom_files[option]['mimetype'] = 'image/png'
|
||||||
|
if option == 'favicon_svg':
|
||||||
|
custom_files[option]['mimetype'] = 'image/svg+xml'
|
||||||
|
else:
|
||||||
|
logger.warning('%s does not exist or is not a file', filepath)
|
||||||
|
|
||||||
|
if 'favicon_svg' in custom_files and 'favicon_png' not in custom_files:
|
||||||
|
logger.warning('Some browsers only support PNG favicons, but you have only set an SVG favicon')
|
||||||
|
|
||||||
|
return custom_files
|
||||||
|
|
||||||
|
|
||||||
def get_result_templates(templates_path):
|
def get_result_templates(templates_path):
|
||||||
result_templates = set()
|
result_templates = set()
|
||||||
templates_path_length = len(templates_path) + 1
|
templates_path_length = len(templates_path) + 1
|
||||||
|
|
|
@ -8,7 +8,6 @@ STATIC_BUILT_PATHS=(
|
||||||
'searx/static/themes/simple/js'
|
'searx/static/themes/simple/js'
|
||||||
'searx/static/themes/simple/src/generated/pygments.less'
|
'searx/static/themes/simple/src/generated/pygments.less'
|
||||||
'searx/static/themes/simple/img'
|
'searx/static/themes/simple/img'
|
||||||
'searx/templates/simple/searxng-wordmark.min.svg'
|
|
||||||
'searx/templates/simple/icons.html'
|
'searx/templates/simple/icons.html'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue