Custom bangs

pull/1132/head
David Shen 3 months ago
parent 7a1ebfe975
commit 963875bdbb
No known key found for this signature in database
GPG Key ID: DDF1B9C8A9AD8CB3

4
.gitignore vendored

@ -1,4 +1,5 @@
venv/ venv/
.venv/
.idea/ .idea/
__pycache__/ __pycache__/
*.pyc *.pyc
@ -10,7 +11,8 @@ test/static
flask_session/ flask_session/
app/static/config app/static/config
app/static/custom_config app/static/custom_config
app/static/bangs app/static/bangs/*
!app/static/bangs/00-whoogle.json
# pip stuff # pip stuff
/build/ /build/

@ -35,6 +35,7 @@ Contents
6. [Extra Steps](#extra-steps) 6. [Extra Steps](#extra-steps)
1. [Set Primary Search Engine](#set-whoogle-as-your-primary-search-engine) 1. [Set Primary Search Engine](#set-whoogle-as-your-primary-search-engine)
2. [Custom Redirecting](#custom-redirecting) 2. [Custom Redirecting](#custom-redirecting)
2. [Custom Bangs](#custom-bangs)
3. [Prevent Downtime (Heroku Only)](#prevent-downtime-heroku-only) 3. [Prevent Downtime (Heroku Only)](#prevent-downtime-heroku-only)
4. [Manual HTTPS Enforcement](#https-enforcement) 4. [Manual HTTPS Enforcement](#https-enforcement)
5. [Using with Firefox Containers](#using-with-firefox-containers) 5. [Using with Firefox Containers](#using-with-firefox-containers)
@ -61,6 +62,7 @@ Contents
- Randomly generated User Agent - Randomly generated User Agent
- Easy to install/deploy - Easy to install/deploy
- DDG-style bang (i.e. `!<tag> <query>`) searches - DDG-style bang (i.e. `!<tag> <query>`) searches
- User-defined [custom bangs](#custom-bangs)
- Optional location-based searching (i.e. results near \<city\>) - Optional location-based searching (i.e. results near \<city\>)
- Optional NoJS mode to view search results in a separate window with JavaScript blocked - Optional NoJS mode to view search results in a separate window with JavaScript blocked
@ -539,6 +541,14 @@ WHOOGLE_REDIRECTS="badA.com:goodA.com,badB.com:goodB.com"
NOTE: Do not include "http(s)://" when defining your redirect. NOTE: Do not include "http(s)://" when defining your redirect.
### Custom Bangs
You can create your own custom bangs. By default, bangs are stored in
`app/static/bangs`. See [`00-whoogle.json`](https://github.com/benbusby/whoogle-search/blob/main/app/static/bangs/00-whoogle.json)
for an example. These are parsed in alphabetical order with later files
overriding bangs set in earlier files, with the exception that DDG bangs
(downloaded to `app/static/bangs/bangs.json`) are always parsed first. Thus,
any custom bangs will always override the DDG ones.
### Prevent Downtime (Heroku only) ### Prevent Downtime (Heroku only)
Part of the deal with Heroku's free tier is that you're allocated 550 hours/month (meaning it can't stay active 24/7), and the app is temporarily shut down after 30 minutes of inactivity. Once it becomes inactive, any Whoogle searches will still work, but it'll take an extra 10-15 seconds for the app to come back online before displaying the result, which can be frustrating if you're in a hurry. Part of the deal with Heroku's free tier is that you're allocated 550 hours/month (meaning it can't stay active 24/7), and the app is temporarily shut down after 30 minutes of inactivity. Once it becomes inactive, any Whoogle searches will still work, but it'll take an extra 10-15 seconds for the app to come back online before displaying the result, which can be frustrating if you're in a hurry.

@ -180,6 +180,7 @@ send_tor_signal(Signal.HEARTBEAT)
warnings.simplefilter('ignore', MarkupResemblesLocatorWarning) warnings.simplefilter('ignore', MarkupResemblesLocatorWarning)
from app import routes # noqa from app import routes # noqa
routes.load_bangs()
# Disable logging from imported modules # Disable logging from imported modules
logging.config.dictConfig({ logging.config.dictConfig({

@ -8,6 +8,7 @@ import re
import urllib.parse as urlparse import urllib.parse as urlparse
import uuid import uuid
import validators import validators
import glob
from datetime import datetime, timedelta from datetime import datetime, timedelta
from functools import wraps from functools import wraps
@ -37,12 +38,37 @@ from cryptography.exceptions import InvalidSignature
from werkzeug.datastructures import MultiDict from werkzeug.datastructures import MultiDict
# Load DDG bang json files only on init # Load DDG bang json files only on init
bang_json = json.load(open(app.config['BANG_FILE'])) or {} bang_json = {}
ac_var = 'WHOOGLE_AUTOCOMPLETE' ac_var = 'WHOOGLE_AUTOCOMPLETE'
autocomplete_enabled = os.getenv(ac_var, '1') autocomplete_enabled = os.getenv(ac_var, '1')
def load_bangs():
global bang_json
bangs = {}
bang_files = glob.glob(os.path.join(app.config['BANG_PATH'], '*.json'))
# Normalize the paths
bang_files = [os.path.normpath(f) for f in bang_files]
# Move the ddg bangs file to the beginning
ddg_bangs_file = os.path.normpath(app.config['BANG_FILE'])
bang_files = sorted([f for f in bang_files if f != ddg_bangs_file])
bang_files.insert(0, ddg_bangs_file)
for i, bang_file in enumerate(bang_files):
try:
bangs |= json.load(open(bang_file))
except json.decoder.JSONDecodeError:
# Ignore decoding error only for the ddg bangs file, since this can
# occur if file is still being written
if i != 0:
raise
bang_json = dict(sorted(bangs.items()))
def get_search_name(tbm): def get_search_name(tbm):
for tab in app.config['HEADER_TABS'].values(): for tab in app.config['HEADER_TABS'].values():
if tab['tbm'] == tbm: if tab['tbm'] == tbm:
@ -174,12 +200,7 @@ def before_request_func():
# Attempt to reload bangs json if not generated yet # Attempt to reload bangs json if not generated yet
if not bang_json and os.path.getsize(app.config['BANG_FILE']) > 4: if not bang_json and os.path.getsize(app.config['BANG_FILE']) > 4:
try: load_bangs()
bang_json = json.load(open(app.config['BANG_FILE']))
except json.decoder.JSONDecodeError:
# Ignore decoding error, can occur if file is still
# being written
pass
@app.after_request @app.after_request

@ -0,0 +1,14 @@
{
"!i": {
"url": "search?q={}&tbm=isch",
"suggestion": "!i (Whoogle Images)"
},
"!v": {
"url": "search?q={}&tbm=vid",
"suggestion": "!v (Whoogle Videos)"
},
"!n": {
"url": "search?q={}&tbm=nws",
"suggestion": "!n (Whoogle News)"
}
}

@ -48,6 +48,13 @@ def test_ddg_bang(client):
assert rv.headers.get('Location').startswith('https://github.com') assert rv.headers.get('Location').startswith('https://github.com')
def test_custom_bang(client):
# Bang at beginning of query
rv = client.get(f'/{Endpoint.search}?q=!i%20whoogle')
assert rv._status_code == 302
assert rv.headers.get('Location').startswith('search?q=')
def test_config(client): def test_config(client):
rv = client.post(f'/{Endpoint.config}', data=demo_config) rv = client.post(f'/{Endpoint.config}', data=demo_config)
assert rv._status_code == 302 assert rv._status_code == 302

Loading…
Cancel
Save