Merge branch 'benbusby:develop' into develop
This commit is contained in:
commit
ad336a857b
29
README.md
29
README.md
|
@ -258,20 +258,21 @@ There are a few optional environment variables available for customizing a Whoog
|
||||||
### Config Environment Variables
|
### Config Environment Variables
|
||||||
These environment variables allow setting default config values, but can be overwritten manually by using the home page config menu. These allow a shortcut for destroying/rebuilding an instance to the same config state every time.
|
These environment variables allow setting default config values, but can be overwritten manually by using the home page config menu. These allow a shortcut for destroying/rebuilding an instance to the same config state every time.
|
||||||
|
|
||||||
| Variable | Description |
|
| Variable | Description |
|
||||||
| ----------------------- | --------------------------------------------------------------- |
|
| ------------------------------ | --------------------------------------------------------------- |
|
||||||
| WHOOGLE_CONFIG_COUNTRY | Filter results by hosting country |
|
| WHOOGLE_CONFIG_COUNTRY | Filter results by hosting country |
|
||||||
| WHOOGLE_CONFIG_LANGUAGE | Set interface and search result language |
|
| WHOOGLE_CONFIG_LANGUAGE | Set interface language |
|
||||||
| WHOOGLE_CONFIG_DARK | Enable dark theme |
|
| WHOOGLE_CONFIG_SEARCH_LANGUAGE | Set search result language |
|
||||||
| WHOOGLE_CONFIG_SAFE | Enable safe searches |
|
| WHOOGLE_CONFIG_BLOCK | Block websites from search results (use comma-separated list) |
|
||||||
| WHOOGLE_CONFIG_ALTS | Use social media site alternatives (nitter, invidious, etc) |
|
| WHOOGLE_CONFIG_DARK | Enable dark theme |
|
||||||
| WHOOGLE_CONFIG_TOR | Use Tor routing (if available) |
|
| WHOOGLE_CONFIG_SAFE | Enable safe searches |
|
||||||
| WHOOGLE_CONFIG_NEW_TAB | Always open results in new tab |
|
| WHOOGLE_CONFIG_ALTS | Use social media site alternatives (nitter, invidious, etc) |
|
||||||
| WHOOGLE_CONFIG_VIEW_IMAGE | Enable View Image option |
|
| WHOOGLE_CONFIG_TOR | Use Tor routing (if available) |
|
||||||
| WHOOGLE_CONFIG_GET_ONLY | Search using GET requests only |
|
| WHOOGLE_CONFIG_NEW_TAB | Always open results in new tab |
|
||||||
| WHOOGLE_CONFIG_URL | The root url of the instance (`https://<your url>/`) |
|
| WHOOGLE_CONFIG_VIEW_IMAGE | Enable View Image option |
|
||||||
| WHOOGLE_CONFIG_STYLE | The custom CSS to use for styling (must be single line) |
|
| WHOOGLE_CONFIG_GET_ONLY | Search using GET requests only |
|
||||||
|
| WHOOGLE_CONFIG_URL | The root url of the instance (`https://<your url>/`) |
|
||||||
|
| WHOOGLE_CONFIG_STYLE | The custom CSS to use for styling (should be single line) |
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
Same as most search engines, with the exception of filtering by time range.
|
Same as most search engines, with the exception of filtering by time range.
|
||||||
|
|
17
app.json
17
app.json
|
@ -71,7 +71,22 @@
|
||||||
"required": false
|
"required": false
|
||||||
},
|
},
|
||||||
"WHOOGLE_CONFIG_LANGUAGE": {
|
"WHOOGLE_CONFIG_LANGUAGE": {
|
||||||
"description": "[CONFIG] The language to use for search results and interface (use values from https://raw.githubusercontent.com/benbusby/whoogle-search/develop/app/static/settings/languages.json)",
|
"description": "[CONFIG] The language to use for the interface (use values from https://raw.githubusercontent.com/benbusby/whoogle-search/develop/app/static/settings/languages.json)",
|
||||||
|
"value": "",
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
"WHOOGLE_CONFIG_SEARCH_LANGUAGE": {
|
||||||
|
"description": "[CONFIG] The language to use for search results (use values from https://raw.githubusercontent.com/benbusby/whoogle-search/develop/app/static/settings/languages.json)",
|
||||||
|
"value": "",
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
"WHOOGLE_CONFIG_DISABLE": {
|
||||||
|
"description": "[CONFIG] Disable ability for client to change config (set to 1 or leave blank)",
|
||||||
|
"value": "",
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
"WHOOGLE_CONFIG_BLOCK": {
|
||||||
|
"description": "[CONFIG] Block websites from search results (comma-separated list)",
|
||||||
"value": "",
|
"value": "",
|
||||||
"required": false
|
"required": false
|
||||||
},
|
},
|
||||||
|
|
|
@ -50,7 +50,7 @@ app.config['BANG_FILE'] = os.path.join(
|
||||||
'bangs.json')
|
'bangs.json')
|
||||||
app.config['CSP'] = 'default-src \'none\';' \
|
app.config['CSP'] = 'default-src \'none\';' \
|
||||||
'manifest-src \'self\';' \
|
'manifest-src \'self\';' \
|
||||||
'img-src \'self\';' \
|
'img-src \'self\' data:;' \
|
||||||
'style-src \'self\' \'unsafe-inline\';' \
|
'style-src \'self\' \'unsafe-inline\';' \
|
||||||
'script-src \'self\';' \
|
'script-src \'self\';' \
|
||||||
'media-src \'self\';' \
|
'media-src \'self\';' \
|
||||||
|
|
|
@ -12,12 +12,13 @@ class Config:
|
||||||
|
|
||||||
app_config = current_app.config
|
app_config = current_app.config
|
||||||
self.url = os.getenv('WHOOGLE_CONFIG_URL', '')
|
self.url = os.getenv('WHOOGLE_CONFIG_URL', '')
|
||||||
self.lang_search = os.getenv('WHOOGLE_CONFIG_LANGUAGE', '')
|
self.lang_search = os.getenv('WHOOGLE_CONFIG_SEARCH_LANGUAGE', '')
|
||||||
self.lang_interface = os.getenv('WHOOGLE_CONFIG_LANGUAGE', '')
|
self.lang_interface = os.getenv('WHOOGLE_CONFIG_LANGUAGE', '')
|
||||||
self.style = os.getenv(
|
self.style = os.getenv(
|
||||||
'WHOOGLE_CONFIG_STYLE',
|
'WHOOGLE_CONFIG_STYLE',
|
||||||
open(os.path.join(app_config['STATIC_FOLDER'],
|
open(os.path.join(app_config['STATIC_FOLDER'],
|
||||||
'css/variables.css')).read())
|
'css/variables.css')).read())
|
||||||
|
self.block = os.getenv('WHOOGLE_CONFIG_BLOCK', '')
|
||||||
self.ctry = os.getenv('WHOOGLE_CONFIG_COUNTRY', '')
|
self.ctry = os.getenv('WHOOGLE_CONFIG_COUNTRY', '')
|
||||||
self.safe = read_config_bool('WHOOGLE_CONFIG_SAFE')
|
self.safe = read_config_bool('WHOOGLE_CONFIG_SAFE')
|
||||||
self.dark = read_config_bool('WHOOGLE_CONFIG_DARK')
|
self.dark = read_config_bool('WHOOGLE_CONFIG_DARK')
|
||||||
|
@ -38,11 +39,12 @@ class Config:
|
||||||
|
|
||||||
# Skip setting custom config if there isn't one
|
# Skip setting custom config if there isn't one
|
||||||
if kwargs:
|
if kwargs:
|
||||||
for attr in self.get_mutable_attrs():
|
mutable_attrs = self.get_mutable_attrs()
|
||||||
if attr not in kwargs.keys():
|
for attr in mutable_attrs:
|
||||||
setattr(self, attr, '')
|
if attr in kwargs.keys():
|
||||||
else:
|
|
||||||
setattr(self, attr, kwargs[attr])
|
setattr(self, attr, kwargs[attr])
|
||||||
|
elif attr not in kwargs.keys() and mutable_attrs[attr] == bool:
|
||||||
|
setattr(self, attr, False)
|
||||||
|
|
||||||
def __getitem__(self, name):
|
def __getitem__(self, name):
|
||||||
return getattr(self, name)
|
return getattr(self, name)
|
||||||
|
@ -57,7 +59,7 @@ class Config:
|
||||||
return hasattr(self, name)
|
return hasattr(self, name)
|
||||||
|
|
||||||
def get_mutable_attrs(self):
|
def get_mutable_attrs(self):
|
||||||
return {name: attr for name, attr in self.__dict__.items()
|
return {name: type(attr) for name, attr in self.__dict__.items()
|
||||||
if not name.startswith("__")
|
if not name.startswith("__")
|
||||||
and (type(attr) is bool or type(attr) is str)}
|
and (type(attr) is bool or type(attr) is str)}
|
||||||
|
|
||||||
|
|
|
@ -120,6 +120,10 @@ def gen_query(query, args, config, near_city=None) -> str:
|
||||||
) if config.lang_interface else ''
|
) if config.lang_interface else ''
|
||||||
param_dict['safe'] = '&safe=' + ('active' if config.safe else 'off')
|
param_dict['safe'] = '&safe=' + ('active' if config.safe else 'off')
|
||||||
|
|
||||||
|
# Block all sites specified in the user config
|
||||||
|
for blocked in config.block.split(','):
|
||||||
|
query += (' -site:' + blocked) if blocked else ''
|
||||||
|
|
||||||
for val in param_dict.values():
|
for val in param_dict.values():
|
||||||
if not val:
|
if not val:
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -2,7 +2,6 @@ import argparse
|
||||||
import base64
|
import base64
|
||||||
import io
|
import io
|
||||||
import json
|
import json
|
||||||
import os
|
|
||||||
import pickle
|
import pickle
|
||||||
import urllib.parse as urlparse
|
import urllib.parse as urlparse
|
||||||
import uuid
|
import uuid
|
||||||
|
@ -17,7 +16,7 @@ from app import app
|
||||||
from app.models.config import Config
|
from app.models.config import Config
|
||||||
from app.request import Request, TorError
|
from app.request import Request, TorError
|
||||||
from app.utils.bangs import resolve_bang
|
from app.utils.bangs import resolve_bang
|
||||||
from app.utils.session import valid_user_session
|
from app.utils.session import generate_user_key, valid_user_session
|
||||||
from app.utils.search import *
|
from app.utils.search import *
|
||||||
|
|
||||||
# Load DDG bang json files only on init
|
# Load DDG bang json files only on init
|
||||||
|
|
|
@ -66,7 +66,7 @@ select {
|
||||||
}
|
}
|
||||||
|
|
||||||
#search-bar {
|
#search-bar {
|
||||||
border: 2px solid var(--whoogle-dark-element-bg) !important;
|
border-color: var(--whoogle-dark-element-bg) !important;
|
||||||
color: var(--whoogle-dark-text) !important;
|
color: var(--whoogle-dark-text) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,11 @@ header {
|
||||||
font-smoothing: antialiased;
|
font-smoothing: antialiased;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.search-bar-desktop {
|
||||||
|
border-radius: 8px 8px 0 0;
|
||||||
|
height: 40px !important;
|
||||||
|
}
|
||||||
|
|
||||||
.search-div {
|
.search-div {
|
||||||
border-radius: 8px 8px 0 0;
|
border-radius: 8px 8px 0 0;
|
||||||
box-shadow: 0 1px 6px rgba(32, 33, 36, 0.18);
|
box-shadow: 0 1px 6px rgba(32, 33, 36, 0.18);
|
||||||
|
@ -37,6 +42,7 @@ header {
|
||||||
height: 39px;
|
height: 39px;
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
margin: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-input {
|
.search-input {
|
||||||
|
@ -61,7 +67,6 @@ header {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#main>div:focus-within {
|
#main>div:focus-within {
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
box-shadow: 0 0 6px 1px #2375e8;
|
box-shadow: 0 0 6px 1px #2375e8;
|
||||||
|
|
14
app/static/css/input.css
Normal file
14
app/static/css/input.css
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#search-bar {
|
||||||
|
background: transparent !important;
|
||||||
|
padding-right: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#search-reset {
|
||||||
|
all: unset;
|
||||||
|
margin-left: -50px;
|
||||||
|
text-align: center;
|
||||||
|
background-color: transparent !important;
|
||||||
|
cursor: pointer;
|
||||||
|
height: 40px;
|
||||||
|
width: 50px;
|
||||||
|
}
|
|
@ -122,6 +122,7 @@ input {
|
||||||
|
|
||||||
.autocomplete-items div:hover {
|
.autocomplete-items div:hover {
|
||||||
background-color: var(--whoogle-element-bg);
|
background-color: var(--whoogle-element-bg);
|
||||||
|
color: var(--whoogle-contrast-text) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.autocomplete-active {
|
.autocomplete-active {
|
||||||
|
|
|
@ -57,4 +57,13 @@ const checkForTracking = () => {
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
checkForTracking();
|
checkForTracking();
|
||||||
|
|
||||||
|
// Clear input if reset button tapped
|
||||||
|
const search = document.getElementById("search-bar");
|
||||||
|
const resetBtn = document.getElementById("search-reset");
|
||||||
|
resetBtn.addEventListener("click", event => {
|
||||||
|
event.preventDefault();
|
||||||
|
search.value = "";
|
||||||
|
search.focus();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
<link rel="search" href="opensearch.xml" type="application/opensearchdescription+xml" title="Whoogle Search">
|
<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="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<meta name="referrer" content="no-referrer">
|
<meta name="referrer" content="no-referrer">
|
||||||
|
<link rel="stylesheet" href="static/css/input.css">
|
||||||
<link rel="stylesheet" href="static/css/search.css">
|
<link rel="stylesheet" href="static/css/search.css">
|
||||||
<link rel="stylesheet" href="static/css/variables.css">
|
<link rel="stylesheet" href="static/css/variables.css">
|
||||||
<link rel="stylesheet" href="static/css/header.css">
|
<link rel="stylesheet" href="static/css/header.css">
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{% if mobile %}
|
{% if mobile %}
|
||||||
<header>
|
<header>
|
||||||
<div class="bz1lBb">
|
<div style="background-color: {{ 'var(--whoogle-dark-result-bg)' if config.dark else 'var(--whoogle-result-bg)' }} !important;" class="bz1lBb">
|
||||||
<form class="Pg70bf" id="search-form" method="POST">
|
<form class="search-form Pg70bf" id="search-form" method="POST">
|
||||||
<a class="logo-link mobile-logo"
|
<a class="logo-link mobile-logo"
|
||||||
href="/"
|
href="/"
|
||||||
style="display:flex; justify-content:center; align-items:center;">
|
style="display:flex; justify-content:center; align-items:center;">
|
||||||
|
@ -11,11 +11,19 @@
|
||||||
</a>
|
</a>
|
||||||
<div class="H0PQec" style="width: 100%;">
|
<div class="H0PQec" style="width: 100%;">
|
||||||
<div class="sbc esbc autocomplete">
|
<div class="sbc esbc autocomplete">
|
||||||
<input id="search-bar" autocapitalize="none" autocomplete="off" class="noHIxc" name="q"
|
<input
|
||||||
style="background-color: {{ 'var(--whoogle-dark-result-bg)' if config.dark else 'var(--whoogle-result-bg)' }} !important;
|
id="search-bar"
|
||||||
color: {{ 'var(--whoogle-dark-text)' if config.dark else 'var(--whoogle-text)' }};
|
autocapitalize="none"
|
||||||
border: {{ '2px solid var(--whoogle-dark-element-bg)' if config.dark else '' }}; border-radius: 8px;"
|
autocomplete="off"
|
||||||
spellcheck="false" type="text" value="{{ query }}">
|
autocorrect="off"
|
||||||
|
spellcheck="false"
|
||||||
|
class="noHIxc"
|
||||||
|
name="q"
|
||||||
|
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)' }};
|
||||||
|
type="text"
|
||||||
|
value="{{ query[:query.find('-site:')] }}">
|
||||||
|
<input style="color: {{ 'var(--whoogle-dark-text)' if config.dark else 'var(--whoogle-text)' }}" id="search-reset" type="reset" value="x">
|
||||||
<input name="tbm" value="{{ search_type }}" style="display: none">
|
<input name="tbm" value="{{ search_type }}" style="display: none">
|
||||||
<input type="submit" style="display: none;">
|
<input type="submit" style="display: none;">
|
||||||
<div class="sc"></div>
|
<div class="sc"></div>
|
||||||
|
@ -37,11 +45,19 @@
|
||||||
<form id="search-form" class="search-form" id="sf" method="POST">
|
<form id="search-form" class="search-form" id="sf" method="POST">
|
||||||
<div class="autocomplete" style="width: 100%; flex: 1">
|
<div class="autocomplete" style="width: 100%; flex: 1">
|
||||||
<div style="width: 100%; display: flex">
|
<div style="width: 100%; display: flex">
|
||||||
<input id="search-bar" autocapitalize="none" autocomplete="off" class="noHIxc" name="q"
|
<input
|
||||||
spellcheck="false" type="text" value="{{ query }}"
|
id="search-bar"
|
||||||
style="background-color: {{ 'var(--whoogle-dark-result-bg)' if config.dark else 'var(--whoogle-result-bg)' }} !important;
|
autocapitalize="none"
|
||||||
color: {{ 'var(--whoogle-dark-text)' if config.dark else 'var(--whoogle-text)' }};
|
autocomplete="off"
|
||||||
border: {{ '2px solid var(--whoogle-dark-element-bg)' if config.dark else '' }}; border-radius: 8px;">
|
autocorrect="off"
|
||||||
|
class="search-bar-desktop noHIxc"
|
||||||
|
name="q"
|
||||||
|
spellcheck="false"
|
||||||
|
type="text"
|
||||||
|
value="{{ query[:query.find('-site:')] }}"
|
||||||
|
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-bottom: {{ '2px solid var(--whoogle-dark-element-bg)' if config.dark else '0px' }};">
|
||||||
<input name="tbm" value="{{ search_type }}" style="display: none">
|
<input name="tbm" value="{{ search_type }}" style="display: none">
|
||||||
<input type="submit" style="display: none;">
|
<input type="submit" style="display: none;">
|
||||||
<div class="sc"></div>
|
<div class="sc"></div>
|
||||||
|
|
|
@ -42,113 +42,137 @@
|
||||||
<form id="search-form" action="search" method="{{ 'get' if config.get_only else 'post' }}">
|
<form id="search-form" action="search" method="{{ 'get' if config.get_only else 'post' }}">
|
||||||
<div class="search-fields">
|
<div class="search-fields">
|
||||||
<div class="autocomplete">
|
<div class="autocomplete">
|
||||||
<input type="text" name="q" id="search-bar" class="home-search" autofocus="autofocus" autocapitalize="none" autocomplete="off">
|
<input
|
||||||
|
type="text"
|
||||||
|
name="q"
|
||||||
|
id="search-bar"
|
||||||
|
class="home-search"
|
||||||
|
autofocus="autofocus"
|
||||||
|
autocapitalize="none"
|
||||||
|
spellcheck="false"
|
||||||
|
autocorrect="off"
|
||||||
|
autocomplete="off">
|
||||||
</div>
|
</div>
|
||||||
<input type="submit" id="search-submit" value="Search">
|
<input type="submit" id="search-submit" value="Search">
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<br/>
|
{% if not config_disabled %}
|
||||||
<button id="config-collapsible" class="collapsible">Configuration</button>
|
<br/>
|
||||||
<div class="content">
|
<button id="config-collapsible" class="collapsible">Configuration</button>
|
||||||
<div class="config-fields">
|
<div class="content">
|
||||||
<form id="config-form" action="config" method="post">
|
<div class="config-fields">
|
||||||
<div class="config-div config-div-ctry">
|
<form id="config-form" action="config" method="post">
|
||||||
<label for="config-ctry">Filter Results by Country: </label>
|
<div class="config-div config-div-ctry">
|
||||||
<select name="ctry" id="config-ctry">
|
<label for="config-ctry">Filter Results by Country: </label>
|
||||||
{% for ctry in countries %}
|
<select name="ctry" id="config-ctry">
|
||||||
<option value="{{ ctry.value }}"
|
{% for ctry in countries %}
|
||||||
{% if ctry.value in config.ctry %}
|
<option value="{{ ctry.value }}"
|
||||||
selected
|
{% if ctry.value in config.ctry %}
|
||||||
{% endif %}>
|
selected
|
||||||
{{ ctry.name }}
|
{% endif %}>
|
||||||
</option>
|
{{ ctry.name }}
|
||||||
{% endfor %}
|
</option>
|
||||||
</select>
|
{% endfor %}
|
||||||
<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>
|
</select>
|
||||||
</div>
|
<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 class="config-div config-div-lang">
|
</div>
|
||||||
<label for="config-lang-interface">Interface Language: </label>
|
<div class="config-div config-div-lang">
|
||||||
<select name="lang_interface" id="config-lang-interface">
|
<label for="config-lang-interface">Interface Language: </label>
|
||||||
{% for lang in languages %}
|
<select name="lang_interface" id="config-lang-interface">
|
||||||
<option value="{{ lang.value }}"
|
{% for lang in languages %}
|
||||||
{% if lang.value in config.lang_interface %}
|
<option value="{{ lang.value }}"
|
||||||
selected
|
{% if lang.value in config.lang_interface %}
|
||||||
{% endif %}>
|
selected
|
||||||
{{ lang.name }}
|
{% endif %}>
|
||||||
</option>
|
{{ lang.name }}
|
||||||
{% endfor %}
|
</option>
|
||||||
</select>
|
{% endfor %}
|
||||||
</div>
|
</select>
|
||||||
<div class="config-div config-div-search-lang">
|
</div>
|
||||||
<label for="config-lang-search">Search Language: </label>
|
<div class="config-div config-div-search-lang">
|
||||||
<select name="lang_search" id="config-lang-search">
|
<label for="config-lang-search">Search Language: </label>
|
||||||
{% for lang in languages %}
|
<select name="lang_search" id="config-lang-search">
|
||||||
<option value="{{ lang.value }}"
|
{% for lang in languages %}
|
||||||
{% if lang.value in config.lang_search %}
|
<option value="{{ lang.value }}"
|
||||||
selected
|
{% if lang.value in config.lang_search %}
|
||||||
{% endif %}>
|
selected
|
||||||
{{ lang.name }}
|
{% endif %}>
|
||||||
</option>
|
{{ lang.name }}
|
||||||
{% endfor %}
|
</option>
|
||||||
</select>
|
{% endfor %}
|
||||||
</div>
|
</select>
|
||||||
<div class="config-div config-div-near">
|
</div>
|
||||||
<label for="config-near">Near: </label>
|
<div class="config-div config-div-near">
|
||||||
<input type="text" name="near" id="config-near" placeholder="City Name" value="{{ config.near }}">
|
<label for="config-near">Near: </label>
|
||||||
</div>
|
<input type="text" name="near" id="config-near" placeholder="City Name" value="{{ config.near }}">
|
||||||
<div class="config-div config-div-nojs">
|
</div>
|
||||||
<label for="config-nojs">Show NoJS Links: </label>
|
<div class="config-div config-div-block">
|
||||||
<input type="checkbox" name="nojs" id="config-nojs" {{ 'checked' if config.nojs else '' }}>
|
<label for="config-block">Block: </label>
|
||||||
</div>
|
<input type="text" name="block" id="config-block" placeholder="Comma-separated site list" value="{{ config.block }}">
|
||||||
<div class="config-div config-div-dark">
|
|
||||||
<label for="config-dark">Dark Mode: </label>
|
|
||||||
<input type="checkbox" name="dark" id="config-dark" {{ 'checked' if config.dark else '' }}>
|
|
||||||
</div>
|
|
||||||
<div class="config-div config-div-safe">
|
|
||||||
<label for="config-safe">Safe Search: </label>
|
|
||||||
<input type="checkbox" name="safe" id="config-safe" {{ 'checked' if config.safe else '' }}>
|
|
||||||
</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" {{ '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 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" {{ 'checked' if config.new_tab else '' }}>
|
|
||||||
</div>
|
|
||||||
<div class="config-div config-div-view-image">
|
|
||||||
<label for="config-view-image">View image: </label>
|
|
||||||
<input type="checkbox" name="view_image" id="config-view-image" {{ 'checked' if config.view_image else '' }}>
|
|
||||||
<div><span class="info-text"> — Adds the "View Image" option to image search results.
|
|
||||||
Note: This will cause image result thumbnails to be lower resolution.</span></div>
|
|
||||||
</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' }} {{ 'checked' if config.tor else '' }}>
|
|
||||||
</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" {{ 'checked' if config.get_only else '' }}>
|
|
||||||
</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="{{ 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" value="Load">
|
|
||||||
<input type="submit" id="config-submit" value="Apply">
|
|
||||||
<input type="submit" id="config-save" value="Save As...">
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="config-div config-div-nojs">
|
||||||
</div>
|
<label for="config-nojs">Show NoJS Links: </label>
|
||||||
|
<input type="checkbox" name="nojs" id="config-nojs" {{ 'checked' if config.nojs else '' }}>
|
||||||
|
</div>
|
||||||
|
<div class="config-div config-div-dark">
|
||||||
|
<label for="config-dark">Dark Mode: </label>
|
||||||
|
<input type="checkbox" name="dark" id="config-dark" {{ 'checked' if config.dark else '' }}>
|
||||||
|
</div>
|
||||||
|
<div class="config-div config-div-safe">
|
||||||
|
<label for="config-safe">Safe Search: </label>
|
||||||
|
<input type="checkbox" name="safe" id="config-safe" {{ 'checked' if config.safe else '' }}>
|
||||||
|
</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" {{ '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 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" {{ 'checked' if config.new_tab else '' }}>
|
||||||
|
</div>
|
||||||
|
<div class="config-div config-div-view-image">
|
||||||
|
<label for="config-view-image">View Image: </label>
|
||||||
|
<input type="checkbox" name="view_image" id="config-view-image" {{ 'checked' if config.view_image else '' }}>
|
||||||
|
<div><span class="info-text"> — Adds the "View Image" option to image search results.
|
||||||
|
Note: This will cause image result thumbnails to be lower resolution.</span></div>
|
||||||
|
</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' }} {{ 'checked' if config.tor else '' }}>
|
||||||
|
</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" {{ 'checked' if config.get_only else '' }}>
|
||||||
|
</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="{{ config.url }}">
|
||||||
|
</div>
|
||||||
|
<div class="config-div config-div-custom-css">
|
||||||
|
<label for="config-style">Custom CSS:</label>
|
||||||
|
<textarea
|
||||||
|
name="style"
|
||||||
|
id="config-style"
|
||||||
|
autocapitalize="off"
|
||||||
|
autocomplete="off"
|
||||||
|
spellcheck="false"
|
||||||
|
autocorrect="off"
|
||||||
|
value="">
|
||||||
|
{{ config.style }}
|
||||||
|
</textarea>
|
||||||
|
</div>
|
||||||
|
<div class="config-div">
|
||||||
|
<input type="submit" id="config-load" value="Load">
|
||||||
|
<input type="submit" id="config-submit" value="Apply">
|
||||||
|
<input type="submit" id="config-save" value="Save As...">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
<footer>
|
<footer>
|
||||||
<p style="color: {{ 'var(--whoogle-dark-text)' if config.dark else 'var(--whoogle-text)' }};">
|
<p style="color: {{ 'var(--whoogle-dark-text)' if config.dark else 'var(--whoogle-text)' }};">
|
||||||
Whoogle Search v{{ version_number }} ||
|
Whoogle Search v{{ version_number }} ||
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
from app.filter import Filter, get_first_link
|
from app.filter import Filter, get_first_link
|
||||||
from app.utils.session import generate_user_key
|
|
||||||
from app.request import gen_query
|
from app.request import gen_query
|
||||||
from bs4 import BeautifulSoup as bsoup
|
from bs4 import BeautifulSoup as bsoup
|
||||||
from cryptography.fernet import Fernet, InvalidToken
|
from cryptography.fernet import Fernet, InvalidToken
|
||||||
|
|
|
@ -37,8 +37,8 @@ services:
|
||||||
#- WHOOGLE_ALT_YT=invidious.snopyta.org
|
#- WHOOGLE_ALT_YT=invidious.snopyta.org
|
||||||
#- WHOOGLE_ALT_IG=bibliogram.art/u
|
#- WHOOGLE_ALT_IG=bibliogram.art/u
|
||||||
#- WHOOGLE_ALT_RD=libredd.it
|
#- WHOOGLE_ALT_RD=libredd.it
|
||||||
# Load environment variables from whoogle.env
|
#env_file: # Alternatively, load variables from whoogle.env
|
||||||
#- WHOOGLE_DOTENV=1
|
#- whoogle.env
|
||||||
ports:
|
ports:
|
||||||
- 5000:5000
|
- 5000:5000
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
|
@ -16,7 +16,7 @@ MarkupSafe==1.1.1
|
||||||
more-itertools==8.3.0
|
more-itertools==8.3.0
|
||||||
packaging==20.4
|
packaging==20.4
|
||||||
pluggy==0.13.1
|
pluggy==0.13.1
|
||||||
py==1.8.1
|
py==1.10.0
|
||||||
pycodestyle==2.6.0
|
pycodestyle==2.6.0
|
||||||
pycparser==2.19
|
pycparser==2.19
|
||||||
pyOpenSSL==19.1.0
|
pyOpenSSL==19.1.0
|
||||||
|
|
|
@ -3,6 +3,9 @@ from app.filter import Filter
|
||||||
from app.utils.session import generate_user_key
|
from app.utils.session import generate_user_key
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from dateutil.parser import *
|
from dateutil.parser import *
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
|
from test.conftest import demo_config
|
||||||
|
|
||||||
|
|
||||||
def get_search_results(data):
|
def get_search_results(data):
|
||||||
|
@ -46,6 +49,29 @@ def test_post_results(client):
|
||||||
assert len(get_search_results(rv.data)) <= 15
|
assert len(get_search_results(rv.data)) <= 15
|
||||||
|
|
||||||
|
|
||||||
|
def test_block_results(client):
|
||||||
|
rv = client.post('/search', data=dict(q='pinterest'))
|
||||||
|
assert rv._status_code == 200
|
||||||
|
|
||||||
|
has_pinterest = False
|
||||||
|
for link in BeautifulSoup(rv.data, 'html.parser').find_all('a', href=True):
|
||||||
|
if 'pinterest.com' in urlparse(link['href']).netloc:
|
||||||
|
has_pinterest = True
|
||||||
|
break
|
||||||
|
|
||||||
|
assert has_pinterest
|
||||||
|
|
||||||
|
demo_config['block'] = 'pinterest.com'
|
||||||
|
rv = client.post('/config', data=demo_config)
|
||||||
|
assert rv._status_code == 302
|
||||||
|
|
||||||
|
rv = client.post('/search', data=dict(q='pinterest'))
|
||||||
|
assert rv._status_code == 200
|
||||||
|
|
||||||
|
for link in BeautifulSoup(rv.data, 'html.parser').find_all('a', href=True):
|
||||||
|
assert 'pinterest.com' not in urlparse(link['href']).netloc
|
||||||
|
|
||||||
|
|
||||||
# TODO: Unit test the site alt method instead -- the results returned
|
# TODO: Unit test the site alt method instead -- the results returned
|
||||||
# are too unreliable for this test in particular.
|
# are too unreliable for this test in particular.
|
||||||
# def test_site_alts(client):
|
# def test_site_alts(client):
|
||||||
|
|
55
whoogle.env
55
whoogle.env
|
@ -1,5 +1,8 @@
|
||||||
# You can set Whoogle environment variables here, but must set
|
# You can set Whoogle environment variables here, but must
|
||||||
# WHOOGLE_DOTENV=1 in your deployment to enable these values
|
# modify your deployment to enable these values:
|
||||||
|
# - Local: Set WHOOGLE_DOTENV=1
|
||||||
|
# - docker-compose: Uncomment the env_file option
|
||||||
|
# - docker: Add "--env-file ./whoogle.env" to your build command
|
||||||
|
|
||||||
#WHOOGLE_ALT_TW=nitter.net
|
#WHOOGLE_ALT_TW=nitter.net
|
||||||
#WHOOGLE_ALT_YT=invidious.snopyta.org
|
#WHOOGLE_ALT_YT=invidious.snopyta.org
|
||||||
|
@ -13,14 +16,44 @@
|
||||||
#WHOOGLE_PROXY_LOC=""
|
#WHOOGLE_PROXY_LOC=""
|
||||||
#HTTPS_ONLY=1
|
#HTTPS_ONLY=1
|
||||||
|
|
||||||
#WHOOGLE_CONFIG_COUNTRY=countryUK # See app/static/settings/countries.json for values
|
# See app/static/settings/countries.json for values
|
||||||
#WHOOGLE_CONFIG_LANGUAGE=lang_en # See app/static/settings/languages.json for values
|
#WHOOGLE_CONFIG_COUNTRY=countryUK
|
||||||
#WHOOGLE_CONFIG_DARK=1 # Dark mode
|
|
||||||
#WHOOGLE_CONFIG_SAFE=1 # Safe searches
|
# See app/static/settings/languages.json for values
|
||||||
#WHOOGLE_CONFIG_ALTS=1 # Use social media site alternatives
|
#WHOOGLE_CONFIG_LANGUAGE=lang_en
|
||||||
#WHOOGLE_CONFIG_TOR=1 # Use Tor if available
|
|
||||||
#WHOOGLE_CONFIG_NEW_TAB=1 # Open results in new tab
|
# See app/static/settings/languages.json for values
|
||||||
#WHOOGLE_CONFIG_VIEW_IMAGE=1 # Enable View Image option
|
#WHOOGLE_CONFIG_SEARCH_LANGUAGE=lang_en
|
||||||
#WHOOGLE_CONFIG_GET_ONLY=1 # Search using GET requests only
|
|
||||||
|
# Disable changing of config from client
|
||||||
|
#WHOOGLE_CONFIG_DISABLE=1
|
||||||
|
|
||||||
|
# Block websites from search results (comma-separated list)
|
||||||
|
#WHOOGLE_CONFIG_BLOCK=pinterest.com,whitehouse.gov
|
||||||
|
|
||||||
|
# Dark mode
|
||||||
|
#WHOOGLE_CONFIG_DARK=1
|
||||||
|
|
||||||
|
# Safe search mode
|
||||||
|
#WHOOGLE_CONFIG_SAFE=1
|
||||||
|
|
||||||
|
# Use social media site alternatives (nitter, bibliogram, etc)
|
||||||
|
#WHOOGLE_CONFIG_ALTS=1
|
||||||
|
|
||||||
|
# Enable "View Image" option
|
||||||
|
#WHOOGLE_CONFIG_VIEW_IMAGE=1
|
||||||
|
|
||||||
|
# Use Tor if available
|
||||||
|
#WHOOGLE_CONFIG_TOR=1
|
||||||
|
|
||||||
|
# Open results in new tab
|
||||||
|
#WHOOGLE_CONFIG_NEW_TAB=1
|
||||||
|
|
||||||
|
# Search using GET requests only (exposes query in logs)
|
||||||
|
#WHOOGLE_CONFIG_GET_ONLY=1
|
||||||
|
|
||||||
|
# Set instance URL
|
||||||
#WHOOGLE_CONFIG_URL=https://<whoogle url>/
|
#WHOOGLE_CONFIG_URL=https://<whoogle url>/
|
||||||
|
|
||||||
|
# Set custom CSS styling/theming
|
||||||
#WHOOGLE_CONFIG_STYLE=":root { /* LIGHT THEME COLORS */ --whoogle-background: #d8dee9; --whoogle-accent: #2e3440; --whoogle-text: #3B4252; --whoogle-contrast-text: #eceff4; --whoogle-secondary-text: #70757a; --whoogle-result-bg: #fff; --whoogle-result-title: #4c566a; --whoogle-result-url: #81a1c1; --whoogle-result-visited: #a3be8c; /* 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; }"
|
#WHOOGLE_CONFIG_STYLE=":root { /* LIGHT THEME COLORS */ --whoogle-background: #d8dee9; --whoogle-accent: #2e3440; --whoogle-text: #3B4252; --whoogle-contrast-text: #eceff4; --whoogle-secondary-text: #70757a; --whoogle-result-bg: #fff; --whoogle-result-title: #4c566a; --whoogle-result-url: #81a1c1; --whoogle-result-visited: #a3be8c; /* 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; }"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user