Allow user-defined CSS/theming (#227)

* Add custom CSS field to config

This allows users to set/customize an instance's theme and appearance to
their liking. The config CSS field is prepopulated with all default CSS
variable values to allow quick editing.

Note that this can be somewhat of a "footgun" if someone updates the
CSS to hide all fields/search/etc. Should probably add some sort of
bandaid "admin" feature for public instances to employ until the whole
cookie/session issue is investigated further.

* Symlink all app static files to test dir

* Refactor app/misc/*.json -> app/static/settings/*.json

The country/language json files are used for user config settings, so
the "misc" name didn't really make sense. Also moved these to the static
folder to make testing easier.

* Fix light theme variables in dark theme css

* Minor style tweaking
pull/264/head
Ben Busby 3 years ago committed by Ben Busby
parent 337d0ebe37
commit 62a9b9e949

@ -18,13 +18,13 @@ app.config['VERSION_NUMBER'] = '0.3.2'
app.config['APP_ROOT'] = os.getenv(
'APP_ROOT',
os.path.dirname(os.path.abspath(__file__)))
app.config['LANGUAGES'] = json.load(open(
os.path.join(app.config['APP_ROOT'], 'misc/languages.json')))
app.config['COUNTRIES'] = json.load(open(
os.path.join(app.config['APP_ROOT'], 'misc/countries.json')))
app.config['STATIC_FOLDER'] = os.getenv(
'STATIC_FOLDER',
os.path.join(app.config['APP_ROOT'], 'static'))
app.config['LANGUAGES'] = json.load(open(
os.path.join(app.config['STATIC_FOLDER'], 'settings/languages.json')))
app.config['COUNTRIES'] = json.load(open(
os.path.join(app.config['STATIC_FOLDER'], 'settings/countries.json')))
app.config['CONFIG_PATH'] = os.getenv(
'CONFIG_VOLUME',
os.path.join(app.config['STATIC_FOLDER'], 'config'))

@ -1,8 +1,15 @@
from flask import current_app
import os
class Config:
def __init__(self, **kwargs):
app_config = current_app.config
self.url = ''
self.lang_search = ''
self.lang_interface = ''
self.style = open(os.path.join(app_config['STATIC_FOLDER'],
'css/variables.css')).read()
self.ctry = ''
self.safe = False
self.dark = False

@ -233,12 +233,12 @@ def search():
'display.html',
query=urlparse.unquote(query),
search_type=search_util.search_type,
dark_mode=g.user_config.dark,
config=g.user_config,
response=response,
version_number=app.config['VERSION_NUMBER'],
search_header=(render_template(
'header.html',
dark_mode=g.user_config.dark,
config=g.user_config,
query=urlparse.unquote(query),
search_type=search_util.search_type,
mobile=g.user_request.mobile)

@ -1,13 +1,17 @@
html {
background-color: #222 !important;
background: var(--whoogle-dark-background) !important;
}
body {
background-color: #222 !important;
background: var(--whoogle-dark-background) !important;
}
div {
color: #fff !important;
color: var(--whoogle-dark-text) !important;
}
label {
color: var(--whoogle-dark-contrast-text) !important;
}
li a {
@ -15,43 +19,114 @@ li a {
}
li {
color: #fff !important;
color: var(--whoogle-dark-text) !important;
}
textarea {
background: var(--whoogle-dark-background) !important;
color: var(--whoogle-dark-text) !important;
}
a:visited h3 div {
color: #bbbbff !important;
color: var(--whoogle-dark-result-visited) !important;
}
a:link h3 div {
color: #4b8eea !important;
color: var(--whoogle-dark-result-title) !important;
}
a:link div {
color: #aaffaa !important;
color: var(--whoogle-dark-result-url) !important;
}
div span {
color: #bbb !important;
color: var(--whoogle-dark-secondary-text) !important;
}
input {
background-color: #111 !important;
color: #fff !important;
background-color: var(--whoogle-dark-background) !important;
color: var(--whoogle-dark-text) !important;
}
#search-bar {
color: #fff !important;
background-color: #222 !important;
select {
background: var(--whoogle-dark-background) !important;
color: var(--whoogle-dark-text) !important;
}
.search-container {
background-color: #222 !important;
background-color: var(--whoogle-dark-background) !important;
}
.ZINbbc {
background-color: var(--whoogle-dark-result-bg) !important;
}
.bRsWnc {
background-color: var(--whoogle-dark-result-bg) !important;
}
#search-bar {
border: 2px solid var(--whoogle-dark-accent) !important;
border-radius: 8px;
color: var(--whoogle-dark-text) !important;
}
#search-bar:focus {
color: var(--whoogle-dark-text) !important;
}
#search-submit {
border: 1px solid var(--whoogle-dark-accent) !important;
background: var(--whoogle-dark-accent) !important;
color: var(--whoogle-dark-background) !important;
}
.info-text {
color: var(--whoogle-dark-contrast-text) !important;
opacity: 75%;
}
.collapsible {
color: var(--whoogle-dark-accent) !important;
}
.collapsible:after {
color: var(--whoogle-dark-accent) !important;
}
.active {
background-color: var(--whoogle-dark-accent) !important;
color: var(--whoogle-dark-contrast-text) !important;
}
.content {
background-color: var(--whoogle-dark-accent) !important;
color: var(--whoogle-contrast-text) !important;
}
.active:after {
color: var(--whoogle-dark-contrast-text);
}
#gh-link {
color: var(--whoogle-dark-accent);
}
.autocomplete-items {
border: 1px solid #685e79;
}
.autocomplete-items div {
color: #fff;
background-color: #222;
border-bottom: 1px solid #242424;
}
.ZINbbc{
background-color: #1a1a1a !important;
.autocomplete-items div:hover {
background-color: #404040;
}
.bRsWnc{
background-color: #1a1a1a !important;
.autocomplete-active {
background-color: var(--whoogle-dark-accent) !important;
color: var(--whoogle-dark-background) !important;
}

@ -0,0 +1,130 @@
html {
background: var(--whoogle-background) !important;
}
body {
background: var(--whoogle-background) !important;
}
div {
color: var(--whoogle-text) !important;
}
label {
color: var(--whoogle-contrast-text) !important;
}
li a {
color: #4b8eaa !important;
}
li {
color: var(--whoogle-text) !important;
}
textarea {
background: var(--whoogle-background) !important;
color: var(--whoogle-text) !important;
}
select {
background: var(--whoogle-background) !important;
color: var(--whoogle-text) !important;
}
.ZINbbc {
background-color: var(--whoogle-result-bg) !important;
}
.bRsWnc {
background-color: var(--whoogle-result-bg) !important;
}
a:visited h3 div {
color: var(--whoogle-result-visited) !important;
}
a:link h3 div {
color: var(--whoogle-result-title) !important;
}
a:link div {
color: var(--whoogle-result-url) !important;
}
div span {
color: var(--whoogle-secondary-text) !important;
}
input {
background-color: var(--whoogle-background) !important;
color: var(--whoogle-text) !important;
}
#search-bar {
color: var(--whoogle-text) !important;
background-color: var(--whoogle-background);
}
.home-search {
border: 3px solid var(--whoogle-accent) !important;
}
.search-container {
background-color: var(--whoogle-background) !important;
}
#search-submit {
border: 1px solid var(--whoogle-accent) !important;
background: var(--whoogle-accent) !important;
color: var(--whoogle-background) !important;
}
.info-text {
color: var(--whoogle-contrast-text) !important;
opacity: 75%;
}
.collapsible {
color: var(--whoogle-accent) !important;
}
.collapsible:after {
color: var(--whoogle-accent) !important;
}
.active {
background-color: var(--whoogle-accent) !important;
color: var(--whoogle-contrast-text) !important;
}
.content {
background-color: var(--whoogle-accent) !important;
color: var(--whoogle-contrast-text) !important;
}
.active:after {
color: var(--whoogle-contrast-text);
}
#gh-link {
color: var(--whoogle-accent);
}
.autocomplete-items {
border: 1px solid #d4d4d4;
}
.autocomplete-items div {
background-color: #fff;
border-bottom: 1px solid #d4d4d4;
}
.autocomplete-items div:hover {
background-color: #e9e9e9;
}
.autocomplete-active {
background-color: var(--whoogle-accent) !important;
color: var(--whoogle-background) !important;
}

@ -10,6 +10,7 @@ body {
}
.search-container {
background: transparent !important;
width: 80%;
position: absolute;
top: 50%;
@ -26,29 +27,21 @@ body {
}
#search-bar {
background: transparent !important;
width: 100%;
border: 3px solid #685e79;
padding: 5px;
height: 40px;
outline: none;
font-size: 24px;
color: #685e79;
border-radius: 10px 10px 0 0;
max-width: 600px;
background: rgba(0, 0, 0, 0);
}
#search-bar:focus {
color: #685e79;
}
#search-submit {
width: 100%;
height: 40px;
border: 1px solid #685e79;
background: #685e79 !important;
text-align: center;
color: #fff;
cursor: pointer;
font-size: 20px;
align-content: center;
@ -70,7 +63,6 @@ button::-moz-focus-inner {
.collapsible {
outline: 0;
background-color: rgba(0, 0, 0, 0);
color: #685e79;
cursor: pointer;
padding: 18px;
width: 100%;
@ -81,14 +73,8 @@ button::-moz-focus-inner {
border-radius: 10px 10px 0 0;
}
.active {
background-color: #685e79;
color: white;
}
.collapsible:after {
content: '\002B';
color: #685e79;
font-weight: bold;
float: right;
margin-left: 5px;
@ -96,7 +82,6 @@ button::-moz-focus-inner {
.active:after {
content: "\2212";
color: white;
}
.content {
@ -104,8 +89,6 @@ button::-moz-focus-inner {
max-height: 0;
overflow: hidden;
transition: max-height 0.2s ease-out;
background-color: #685e79;
color: white;
border-radius: 0 0 10px 10px;
}
@ -113,12 +96,6 @@ button::-moz-focus-inner {
padding-bottom: 20px;
}
.ua-span {
color: white;
-webkit-box-decoration-break: clone;
box-decoration-break: clone;
}
.hidden {
display: none;
}
@ -135,3 +112,49 @@ footer {
font-style: italic;
font-size: 12px;
}
#config-style {
resize: none;
overflow-y: scroll;
width: 100%;
height: 100px;
}
.whoogle-logo {
display: none;
}
.whoogle-svg {
width: 80%;
display: block;
margin: auto;
padding-bottom: 10px;
}
.autocomplete {
position: relative;
display: inline-block;
width: 100%;
}
.autocomplete-items {
position: absolute;
border-bottom: none;
border-top: none;
z-index: 99;
/*position the autocomplete items to be the same width as the container:*/
top: 100%;
left: 0;
right: 0;
}
.autocomplete-items div {
padding: 10px;
cursor: pointer;
}
details summary {
padding: 10px;
font-weight: bold;
}

@ -1,40 +0,0 @@
.autocomplete {
position: relative;
display: inline-block;
width: 100%;
}
.autocomplete-items {
position: absolute;
border: 1px solid #685e79;
border-bottom: none;
border-top: none;
z-index: 99;
/*position the autocomplete items to be the same width as the container:*/
top: 100%;
left: 0;
right: 0;
}
.autocomplete-items div {
padding: 10px;
cursor: pointer;
color: #fff;
background-color: #222;
border-bottom: 1px solid #242424;
}
.autocomplete-items div:hover {
background-color: #404040;
}
.autocomplete-active {
background-color: #685e79 !important;
color: #ffffff;
}
details summary {
padding: 10px;
font-weight: bold;
}

@ -1,39 +0,0 @@
.autocomplete {
position: relative;
display: inline-block;
width: 100%;
}
.autocomplete-items {
position: absolute;
border: 1px solid #d4d4d4;
border-bottom: none;
border-top: none;
z-index: 99;
/*position the autocomplete items to be the same width as the container:*/
top: 100%;
left: 0;
right: 0;
}
.autocomplete-items div {
padding: 10px;
cursor: pointer;
background-color: #fff;
border-bottom: 1px solid #d4d4d4;
}
.autocomplete-items div:hover {
background-color: #e9e9e9;
}
.autocomplete-active {
background-color: #685e79 !important;
color: #ffffff;
}
details summary {
padding: 10px;
font-weight: bold;
}

@ -0,0 +1,24 @@
/* Colors */
:root {
/* LIGHT THEME COLORS */
--whoogle-background: #fff;
--whoogle-accent: #685e79;
--whoogle-text: #000;
--whoogle-contrast-text: #fff;
--whoogle-secondary-text: #70757a;
--whoogle-result-bg: #fff;
--whoogle-result-title: #1967d2;
--whoogle-result-url: #0d652d;
--whoogle-result-visited: #4b11a8;
/* DARK THEME COLORS */
--whoogle-dark-background: #222;
--whoogle-dark-accent: #685e79;
--whoogle-dark-text: #fff;
--whoogle-dark-contrast-text: #000;
--whoogle-dark-secondary-text: #bbb;
--whoogle-dark-result-bg: #000;
--whoogle-dark-result-title: #1967d2;
--whoogle-dark-result-url: #4b11a8;
--whoogle-dark-result-visited: #bbbbff;
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.0 KiB

@ -1,14 +1,3 @@
// Whoogle configurations that use boolean values and checkboxes
CONFIG_BOOLS = [
"nojs", "dark", "safe", "alts", "new_tab", "get_only", "tor"
];
// Whoogle configurations that use string values and input fields
CONFIG_STRS = [
"near", "url"
];
const setupSearchLayout = () => {
// Setup search field
const searchBar = document.getElementById("search-bar");
@ -28,33 +17,6 @@ const setupSearchLayout = () => {
});
};
const fillConfigValues = () => {
// Request existing config info
let xhrGET = new XMLHttpRequest();
xhrGET.open("GET", "config");
xhrGET.onload = function() {
if (xhrGET.readyState === 4 && xhrGET.status !== 200) {
alert("Error loading Whoogle config");
return;
}
// Allow for updating/saving config values
let configSettings = JSON.parse(xhrGET.responseText);
CONFIG_STRS.forEach(function(item) {
let configElement = document.getElementById("config-" + item.replace("_", "-"));
configElement.value = configSettings[item] ? configSettings[item] : "";
});
CONFIG_BOOLS.forEach(function(item) {
let configElement = document.getElementById("config-" + item.replace("_", "-"));
configElement.checked = !!configSettings[item];
});
};
xhrGET.send();
};
const setupConfigLayout = () => {
// Setup whoogle config
const collapsible = document.getElementById("config-collapsible");
@ -69,8 +31,6 @@ const setupConfigLayout = () => {
content.classList.toggle("open");
});
fillConfigValues();
};
const loadConfig = event => {

@ -5,11 +5,10 @@
<link rel="search" href="opensearch.xml" type="application/opensearchdescription+xml" title="Whoogle Search">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="referrer" content="no-referrer">
<link rel="stylesheet" href="static/css/{{ 'search-dark' if dark_mode else 'search' }}.css">
<link rel="stylesheet" href="static/css/variables.css">
<link rel="stylesheet" href="static/css/header.css">
{% if dark_mode %}
<link rel="stylesheet" href="static/css/dark-theme.css"/>
{% endif %}
<link rel="stylesheet" href="static/css/{{ 'dark' if config.dark else 'light' }}-theme.css"/>
<style>{{ config.style }}</style>
<title>{{ query }} - Whoogle Search</title>
</head>
<body>
@ -17,7 +16,7 @@
{{ response|safe }}
</body>
<footer>
<p style="color: {{ '#fff' if dark_mode else '#000' }};">
<p style="color: {{ '#fff' if config.dark else '#000' }};">
Whoogle Search v{{ version_number }} ||
<a style="color: #685e79" href="https://github.com/benbusby/whoogle-search">View on GitHub</a>
</p>

@ -5,14 +5,14 @@
<a class="logo-link mobile-logo"
href="/"
style="display:flex; justify-content:center; align-items:center; color:#685e79; font-size:18px; ">
<span style="color: #685e79">Whoogle</span>
<span style="color: {{ 'var(--whoogle-dark-accent)' if config.dark else 'var(--whoogle-accent)' }} !important">Whoogle</span>
</a>
<div class="H0PQec" style="width: 100%;">
<div class="sbc esbc autocomplete">
<input id="search-bar" autocapitalize="none" autocomplete="off" class="noHIxc" name="q"
style="background-color: {{ '#000' if dark_mode else '#fff' }};
color: {{ '#685e79' if dark_mode else '#000' }};
border: {{ '1px solid #685e79' if dark_mode else '' }}"
style="background-color: {{ 'var(--whoogle-dark-result-bg)' if config.dark else 'var(--whoogle-result-bg)' }} !important;
color: {{ 'var(--whoogle-dark-text)' if config.dark else 'var(--whoogle-text)' }};
border: {{ '2px solid var(--whoogle-dark-accent)' if config.dark else '' }};"
spellcheck="false" type="text" value="{{ query }}">
<input name="tbm" value="{{ search_type }}" style="display: none">
<input type="submit" style="display: none;">
@ -26,7 +26,7 @@
<header>
<div class="logo-div">
<a class="logo-link" href="/">
<span style="color: #685e79">Whoogle</span>
<span style="color: {{ 'var(--whoogle-dark-accent)' if config.dark else 'var(--whoogle-accent)' }} !important">Whoogle</span>
</a>
</div>
<div class="search-div">
@ -35,9 +35,9 @@
<div style="width: 100%; display: flex">
<input id="search-bar" autocapitalize="none" autocomplete="off" class="noHIxc" name="q"
spellcheck="false" type="text" value="{{ query }}"
style="background-color: {{ '#000' if dark_mode else '#fff' }};
color: {{ '#685e79' if dark_mode else '#000' }};
border: {{ '1px solid #685e79' if dark_mode else '' }}">
style="background-color: {{ 'var(--whoogle-dark-result-bg)' if config.dark else 'var(--whoogle-result-bg)' }} !important;
color: {{ 'var(--whoogle-dark-text)' if config.dark else 'var(--whoogle-text)' }};
border: {{ '2px solid var(--whoogle-dark-accent)' if config.dark else '' }};">
<input name="tbm" value="{{ search_type }}" style="display: none">
<input type="submit" style="display: none;">
<div class="sc"></div>

@ -21,27 +21,50 @@
<script type="text/javascript" src="static/js/controller.js"></script>
<link rel="search" href="opensearch.xml" type="application/opensearchdescription+xml" title="Whoogle Search">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="static/css/{{ 'search-dark' if config.dark else 'search' }}.css">
<link rel="stylesheet" href="static/css/variables.css">
<link rel="stylesheet" href="static/css/main.css">
{% if config.dark %}
<link rel="stylesheet" href="static/css/dark-theme.css"/>
{% endif %}
<link rel="stylesheet" href="static/css/{{ 'dark' if config.dark else 'light' }}-theme.css"/>
<noscript>
<style>
#main { display: inherit !important; }
.content { max-height: 520px; padding: 18px; border-radius: 10px; }
.content { max-height: 720px; padding: 18px; border-radius: 10px; }
.collapsible { display: none; }
</style>
</noscript>
<style>{{ config.style }}</style>
<title>Whoogle Search</title>
</head>
<body id="main" style="display: none; background-color: {{ '#000' if config.dark else '#fff' }}">
<div class="search-container">
<img class="logo" src="static/img/logo.png">
<img class="whoogle-logo" src="static/img/whoogle.svg">
<svg id="Layer_1" class="whoogle-svg" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1028 254">
<defs>
<style>
.cls-1 {
fill: transparent;
}
path {
fill: {{ 'var(--whoogle-dark-accent)' if config.dark else 'var(--whoogle-accent)' }};
}
</style>
</defs>
<path class="cls-1" d="M1197,667H446V413H1474V667H1208a26.41,26.41,0,0,1,4.26-1.16c32.7-3.35,55.65-27.55,56.45-60.44.57-23.65.27-47.33.32-71,0-17.84-.16-35.67.11-53.5.07-4.92-1.57-6.54-6.3-6.11a74.65,74.65,0,0,1-11,0c-3.63-.2-5.18,1.13-5,4.87.22,4.22.05,8.45.05,12.68a6.16,6.16,0,0,1-3.78-2c-20-23.41-53.18-26.6-77.53-7.84-34,26.17-33.8,79.89-7.68,107.44,24.9,26.24,66,24.37,85.69-1.54a14.39,14.39,0,0,1,2.73-2c0,6.94.39,13.22-.08,19.42-1.18,15.5-7.79,28.06-22.32,34.72-15,6.85-30.27,7.21-44-2.92-5.82-4.28-10.1-10.66-15.66-16.71l-19.87,8.29c8.77,16.61,20.28,29.09,38.17,34.48C1187.28,665.12,1192.18,665.92,1197,667ZM447.16,414.27c.39,1.85.57,3,.86,4q25.22,91.07,50.4,182.12c.92,3.32,2.43,4.55,5.92,4.29a82,82,0,0,1,13.48,0c4.6.43,6.56-1.13,8-5.68,12.37-38.63,25-77.15,37.66-115.7.52-1.6,1.26-3.12,1.89-4.67l1.35.06c.81,2.26,1.68,4.51,2.42,6.79q18.62,57.13,37.12,114.31c1.13,3.5,2.61,5.23,6.58,4.89a80.69,80.69,0,0,1,14,0c4.15.37,5.75-1.19,6.79-5.11Q655,518.89,676.57,438.23c2.07-7.78,4.06-15.58,6.24-24-6.92,0-13.07.29-19.19-.11-4.21-.27-5.6,1.31-6.59,5.25q-17.61,70.1-35.6,140.11c-.42,1.61-1.07,3.17-1.62,4.75a10,10,0,0,1-3.16-4.88q-17.11-51.6-34.21-103.21c-1.72-5.19-2.29-12.33-6-14.86-3.9-2.7-10.86-.78-16.45-1.28-4.1-.37-5.73,1.25-7,5.08q-18.7,57.12-37.79,114.11c-.59,1.77-1.43,3.45-2.15,5.18a9.31,9.31,0,0,1-2.68-4.69Q500.5,522.88,490.62,486c-6-22.47-12-45-18.13-67.39-.44-1.63-2-4.13-3.12-4.19C462.13,414.08,454.86,414.27,447.16,414.27ZM1473.38,543.71c-1-8.62-1.16-16.45-2.77-24-5.08-23.65-18.41-40.82-42.31-47.12-24.75-6.52-47.33-2-65,18.14-15.82,18.09-19.77,39.44-16.45,62.6,4,27.73,26.6,52.65,58.1,54.81,21.42,1.46,39.91-3.91,54.24-20.46,3.51-4.05,6.13-8.88,9.54-13.92l-20.94-8.68c-13.71,20.22-30.84,26.7-50.55,19.53-17.08-6.21-29-23.88-27.23-40.92Zm-746-51.07-1.12-.55V414.65H703.69V604.22h23v-6.36c0-21.84-.08-43.68,0-65.52.07-11.59,3.84-21.92,11.82-30.46,9.41-10.07,21.15-11.89,34-8.78,11.13,2.72,17.67,10.23,20.26,21.14a55.72,55.72,0,0,1,1.46,12.34c.13,24,.07,48,.07,72v5.6h23.49v-4.87c0-24.84.05-49.68-.06-74.52a101.29,101.29,0,0,0-1.06-13.91c-2.8-19.45-15.29-34.48-32.34-38.55-21.17-5-39.58-.47-54.11,16.51C729.19,490.07,728.29,491.38,727.34,492.64Zm179.93-22.47c-38.65,0-66.92,28.86-67,68.47-.06,40.49,28.07,70,66.72,70,38.38,0,66.64-29.26,66.67-69C973.71,499.1,946.09,470.21,907.27,470.17Zm82.22,69.31c.57,5.12.76,10.32,1.76,15.35,10.69,53.81,69.71,66.73,104.35,41.39,20.15-14.74,27.8-35.52,27.31-60.14-.88-44.18-40.84-78.15-90-62.12C1006.24,482.67,989.72,508.59,989.49,539.48Zm333.81,64.95V414.62h-22.65V604.43Z" transform="translate(-446 -413)"/>
<path d="M1197,667c-4.82-1.08-9.72-1.88-14.44-3.3-17.89-5.39-29.4-17.87-38.17-34.48l19.87-8.29c5.56,6.05,9.84,12.43,15.66,16.71,13.75,10.13,29.07,9.77,44,2.92,14.53-6.66,21.14-19.22,22.32-34.72.47-6.2.08-12.48.08-19.42a14.39,14.39,0,0,0-2.73,2c-19.7,25.91-60.79,27.78-85.69,1.54-26.12-27.55-26.3-81.27,7.68-107.44,24.35-18.76,57.56-15.57,77.53,7.84a6.16,6.16,0,0,0,3.78,2c0-4.23.17-8.46-.05-12.68-.19-3.74,1.36-5.07,5-4.87a74.65,74.65,0,0,0,11,0c4.73-.43,6.37,1.19,6.3,6.11-.27,17.83-.08,35.66-.11,53.5,0,23.67.25,47.35-.32,71-.8,32.89-23.75,57.09-56.45,60.44A26.41,26.41,0,0,0,1208,667Zm50-127.58c-.58-4.61-.86-9.29-1.79-13.83a42.26,42.26,0,0,0-37.31-33.75c-16.16-1.75-33.25,8.46-40.62,24.47-5.34,11.62-5.79,23.83-3.48,36.18,5.94,31.62,42.76,45.77,66.74,25.67C1242.58,568.08,1246.76,554.62,1247,539.42Z" transform="translate(-446 -413)"/>
<path d="M447.16,414.27c7.7,0,15-.19,22.21.19,1.14.06,2.68,2.56,3.12,4.19,6.13,22.44,12.1,44.92,18.13,67.39q9.88,36.84,19.81,73.66a9.31,9.31,0,0,0,2.68,4.69c.72-1.73,1.56-3.41,2.15-5.18q19-57,37.79-114.11c1.25-3.83,2.88-5.45,7-5.08,5.59.5,12.55-1.42,16.45,1.28,3.67,2.53,4.24,9.67,6,14.86q17.14,51.58,34.21,103.21a10,10,0,0,0,3.16,4.88c.55-1.58,1.2-3.14,1.62-4.75q17.87-70,35.6-140.11c1-3.94,2.38-5.52,6.59-5.25,6.12.4,12.27.11,19.19.11-2.18,8.4-4.17,16.2-6.24,24q-21.5,80.68-42.93,161.39c-1,3.92-2.64,5.48-6.79,5.11a80.69,80.69,0,0,0-14,0c-4,.34-5.45-1.39-6.58-4.89q-18.43-57.2-37.12-114.31c-.74-2.28-1.61-4.53-2.42-6.79l-1.35-.06c-.63,1.55-1.37,3.07-1.89,4.67-12.61,38.55-25.29,77.07-37.66,115.7-1.46,4.55-3.42,6.11-8,5.68a82,82,0,0,0-13.48,0c-3.49.26-5-1-5.92-4.29Q473.31,509.34,448,418.3C447.73,417.23,447.55,416.12,447.16,414.27Z" transform="translate(-446 -413)"/>
<path d="M1473.38,543.71H1370c-1.76,17,10.15,34.71,27.23,40.92,19.71,7.17,36.84.69,50.55-19.53l20.94,8.68c-3.41,5-6,9.87-9.54,13.92-14.33,16.55-32.82,21.92-54.24,20.46-31.5-2.16-54.12-27.08-58.1-54.81-3.32-23.16.63-44.51,16.45-62.6,17.64-20.17,40.22-24.66,65-18.14,23.9,6.3,37.23,23.47,42.31,47.12C1472.22,527.26,1472.43,535.09,1473.38,543.71Zm-26.69-19.8c2.09-14-14.21-30.54-31.43-32.19-22.21-2.13-43.06,13.12-43.63,32.19Z" transform="translate(-446 -413)"/>
<path d="M727.34,492.64c.95-1.26,1.85-2.57,2.88-3.77,14.53-17,32.94-21.55,54.11-16.51,17,4.07,29.54,19.1,32.34,38.55a101.29,101.29,0,0,1,1.06,13.91c.11,24.84.06,49.68.06,74.52v4.87H794.3v-5.6c0-24,.06-48-.07-72a55.72,55.72,0,0,0-1.46-12.34c-2.59-10.91-9.13-18.42-20.26-21.14-12.81-3.11-24.55-1.29-34,8.78-8,8.54-11.75,18.87-11.82,30.46-.12,21.84,0,43.68,0,65.52v6.36h-23V414.65h22.53v77.44Z" transform="translate(-446 -413)"/>
<path d="M907.27,470.17c38.82,0,66.44,28.93,66.41,69.47,0,39.73-28.29,69-66.67,69-38.65,0-66.78-29.5-66.72-70C840.35,499,868.62,470.13,907.27,470.17Zm43.24,69.26c-.43-3.79-.72-7.61-1.31-11.37-2.94-18.67-19.1-34.56-36.86-36.35-19.93-2-37.94,8.92-45,27.58-3.74,9.85-4.19,20-2.68,30.44,4,27.42,32.55,44.52,57.87,34.41C939.6,577.32,950.2,560.25,950.51,539.43Z" transform="translate(-446 -413)"/>
<path d="M989.49,539.48c.23-30.89,16.75-56.81,43.45-65.52,49.13-16,89.09,17.94,90,62.12.49,24.62-7.16,45.4-27.31,60.14-34.64,25.34-93.66,12.42-104.35-41.39C990.25,549.8,990.06,544.6,989.49,539.48Zm110.22-.09c-.48-4.29-.7-8.62-1.5-12.84-3.43-18.06-19.37-33.16-36.57-34.84-20.05-2-37.75,8.9-45,27.62-3.51,9.06-3.74,18.45-3,28,2.23,27.4,30.07,46.21,55.87,37.67C1088,578.9,1099.32,561.53,1099.71,539.39Z" transform="translate(-446 -413)"/>
<path d="M1323.3,604.43h-22.65V414.62h22.65Z" transform="translate(-446 -413)"/>
<path class="cls-1" d="M1247,539.42c-.24,15.2-4.42,28.66-16.46,38.74-24,20.1-60.8,6-66.74-25.67-2.31-12.35-1.86-24.56,3.48-36.18,7.37-16,24.46-26.22,40.62-24.47a42.26,42.26,0,0,1,37.31,33.75C1246.14,530.13,1246.42,534.81,1247,539.42Z" transform="translate(-446 -413)"/>
<path class="cls-1" d="M1446.69,523.91h-75.06c.57-19.07,21.42-34.32,43.63-32.19C1432.48,493.37,1448.78,509.88,1446.69,523.91Z" transform="translate(-446 -413)"/>
<path class="cls-1" d="M950.51,539.43c-.31,20.82-10.91,37.89-28,44.71-25.32,10.11-53.89-7-57.87-34.41-1.51-10.43-1.06-20.59,2.68-30.44,7.08-18.66,25.09-29.59,45-27.58,17.76,1.79,33.92,17.68,36.86,36.35C949.79,531.82,950.08,535.64,950.51,539.43Z" transform="translate(-446 -413)"/>
<path class="cls-1" d="M1099.71,539.39c-.39,22.14-11.74,39.51-30.16,45.6-25.8,8.54-53.64-10.27-55.87-37.67-.78-9.54-.55-18.93,3-28,7.25-18.72,24.95-29.59,45-27.62,17.2,1.68,33.14,16.78,36.57,34.84C1099,530.77,1099.23,535.1,1099.71,539.39Z" transform="translate(-446 -413)"/>
</svg>
<form id="search-form" action="search" method="{{ 'get' if config.get_only else 'post' }}">
<div class="search-fields">
<div class="autocomplete">
<input type="text" name="q" id="search-bar" autofocus="autofocus" autocapitalize="none" autocomplete="off">
<input type="text" name="q" id="search-bar" class="home-search" autofocus="autofocus" autocapitalize="none" autocomplete="off">
</div>
<input type="submit" id="search-submit" value="Search">
</div>
@ -51,7 +74,7 @@
<div class="content">
<div class="config-fields">
<form id="config-form" action="config" method="post">
<div class="config-div">
<div class="config-div config-div-ctry">
<label for="config-ctry">Filter Results by Country: </label>
<select name="ctry" id="config-ctry">
{% for ctry in countries %}
@ -65,7 +88,7 @@
</select>
<div><span class="info-text"> — Note: If enabled, a website will only appear in the results if it is *hosted* in the selected country.</span></div>
</div>
<div class="config-div">
<div class="config-div config-div-lang">
<label for="config-lang-interface">Interface Language: </label>
<select name="lang_interface" id="config-lang-interface">
{% for lang in languages %}
@ -78,7 +101,7 @@
{% endfor %}
</select>
</div>
<div class="config-div">
<div class="config-div config-div-search-lang">
<label for="config-lang-search">Search Language: </label>
<select name="lang_search" id="config-lang-search">
{% for lang in languages %}
@ -91,43 +114,47 @@
{% endfor %}
</select>
</div>
<div class="config-div">
<div class="config-div config-div-near">
<label for="config-near">Near: </label>
<input type="text" name="near" id="config-near" placeholder="City Name">
<input type="text" name="near" id="config-near" placeholder="City Name" value="{{ config.near }}">
</div>
<div class="config-div">
<div class="config-div config-div-nojs">
<label for="config-nojs">Show NoJS Links: </label>
<input type="checkbox" name="nojs" id="config-nojs">
<input type="checkbox" name="nojs" id="config-nojs" {{ 'checked' if config.nojs else '' }}>
</div>
<div class="config-div">
<div class="config-div config-div-dark">
<label for="config-dark">Dark Mode: </label>
<input type="checkbox" name="dark" id="config-dark">
<input type="checkbox" name="dark" id="config-dark" {{ 'checked' if config.dark else '' }}>
</div>
<div class="config-div">
<div class="config-div config-div-safe">
<label for="config-safe">Safe Search: </label>
<input type="checkbox" name="safe" id="config-safe">
<input type="checkbox" name="safe" id="config-safe" {{ 'checked' if config.safe else '' }}>
</div>
<div class="config-div">
<div class="config-div config-div-alts">
<label class="tooltip" for="config-alts">Replace Social Media Links: </label>
<input type="checkbox" name="alts" id="config-alts">
<input type="checkbox" name="alts" id="config-alts" {{ 'checked' if config.alts else '' }}>
<div><span class="info-text"> — Replaces Twitter/YouTube/Instagram/Reddit links
with Nitter/Invidious/Bibliogram/Libreddit links.</span></div>
</div>
<div class="config-div">
<div class="config-div config-div-new-tab">
<label for="config-new-tab">Open Links in New Tab: </label>
<input type="checkbox" name="new_tab" id="config-new-tab">
<input type="checkbox" name="new_tab" id="config-new-tab" {{ 'checked' if config.new_tab else '' }}>
</div>
<div class="config-div">
<div class="config-div config-div-tor">
<label for="config-tor">Use Tor: {{ '' if tor_available else 'Unavailable' }}</label>
<input type="checkbox" name="tor" id="config-tor" {{ '' if tor_available else 'hidden' }}>
<input type="checkbox" name="tor" id="config-tor" {{ '' if tor_available else 'hidden' }} {{ 'checked' if config.tor else '' }}>
</div>
<div class="config-div">
<div class="config-div config-div-get-only">
<label for="config-get-only">GET Requests Only: </label>
<input type="checkbox" name="get_only" id="config-get-only">
<input type="checkbox" name="get_only" id="config-get-only" {{ 'checked' if config.get_only else '' }}>
</div>
<div class="config-div">
<div class="config-div config-div-root-url">
<label for="config-url">Root URL: </label>
<input type="text" name="url" id="config-url" value="">
<input type="text" name="url" id="config-url" value="{{ config.url }}">
</div>
<div class="config-div config-div-custom-css">
<label for="config-style">Custom CSS:</label>
<textarea name="style" id="config-style" value="">{{ config.style }}</textarea>
</div>
<div class="config-div">
<input type="submit" id="config-load" onclick="loadConfig(event)" value="Load">&nbsp;
@ -141,7 +168,7 @@
<footer>
<p style="color: {{ '#fff' if config.dark else '#000' }};">
Whoogle Search v{{ version_number }} ||
<a style="color: #685e79" href="https://github.com/benbusby/whoogle-search">View on GitHub</a>
<a id="gh-link" href="https://github.com/benbusby/whoogle-search">View on GitHub</a>
</p>
</footer>
</body>

6
run

@ -12,12 +12,14 @@ SUBDIR="${1:-app}"
export APP_ROOT="$SCRIPT_DIR/$SUBDIR"
export STATIC_FOLDER="$APP_ROOT/static"
mkdir -p "$STATIC_FOLDER"
# Check for regular vs test run
if [[ "$SUBDIR" == "test" ]]; then
# Set up static files for testing
rm -rf "$STATIC_FOLDER"
ln -s "$SCRIPT_DIR/app/static" "$STATIC_FOLDER"
pytest -sv
else
mkdir -p "$STATIC_FOLDER"
python3 -um app \
--host "${ADDRESS:-0.0.0.0}" \
--port "${PORT:-"${EXPOSE_PORT:-5000}"}"

@ -1 +0,0 @@
../app/misc/
Loading…
Cancel
Save