We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Double bangs without query redirect to search URL instead of main page
<!-- PLEASE FILL THESE FIELDS, IT REALLY HELPS THE MAINTAINERS OF SearXNG -->

**Version of SearXNG, commit number if you are using on master branch and stipulate if you forked SearXNG**
`2023.4.21+98387e29`

**How did you install SearXNG?**
`searxng-docker`

**What happened?**
Double bangs without query redirect to search URL instead of main page

**How To Reproduce**
Use external bang without any search items e.g. `!!gh` and we land on `https://github.com/search?utf8=%E2%9C%93&q=` 

**Expected behavior**
`!!gh` should redirect to `https://github.com` if no search items

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `searx/external_bang.py`
Content:
```
1 # SPDX-License-Identifier: AGPL-3.0-or-later
2 
3 from urllib.parse import quote_plus
4 from searx.data import EXTERNAL_BANGS
5 
6 LEAF_KEY = chr(16)
7 
8 
9 def get_node(external_bangs_db, bang):
10     node = external_bangs_db['trie']
11     after = ''
12     before = ''
13     for bang_letter in bang:
14         after += bang_letter
15         if after in node and isinstance(node, dict):
16             node = node[after]
17             before += after
18             after = ''
19     return node, before, after
20 
21 
22 def get_bang_definition_and_ac(external_bangs_db, bang):
23     node, before, after = get_node(external_bangs_db, bang)
24 
25     bang_definition = None
26     bang_ac_list = []
27     if after != '':
28         for k in node:
29             if k.startswith(after):
30                 bang_ac_list.append(before + k)
31     elif isinstance(node, dict):
32         bang_definition = node.get(LEAF_KEY)
33         bang_ac_list = [before + k for k in node.keys() if k != LEAF_KEY]
34     elif isinstance(node, str):
35         bang_definition = node
36         bang_ac_list = []
37 
38     return bang_definition, bang_ac_list
39 
40 
41 def resolve_bang_definition(bang_definition, query):
42     url, rank = bang_definition.split(chr(1))
43     url = url.replace(chr(2), quote_plus(query))
44     if url.startswith('//'):
45         url = 'https:' + url
46     rank = int(rank) if len(rank) > 0 else 0
47     return (url, rank)
48 
49 
50 def get_bang_definition_and_autocomplete(bang, external_bangs_db=None):
51     if external_bangs_db is None:
52         external_bangs_db = EXTERNAL_BANGS
53 
54     bang_definition, bang_ac_list = get_bang_definition_and_ac(external_bangs_db, bang)
55 
56     new_autocomplete = []
57     current = [*bang_ac_list]
58     done = set()
59     while len(current) > 0:
60         bang_ac = current.pop(0)
61         done.add(bang_ac)
62 
63         current_bang_definition, current_bang_ac_list = get_bang_definition_and_ac(external_bangs_db, bang_ac)
64         if current_bang_definition:
65             _, order = resolve_bang_definition(current_bang_definition, '')
66             new_autocomplete.append((bang_ac, order))
67         for new_bang in current_bang_ac_list:
68             if new_bang not in done and new_bang not in current:
69                 current.append(new_bang)
70 
71     new_autocomplete.sort(key=lambda t: (-t[1], t[0]))
72     new_autocomplete = list(map(lambda t: t[0], new_autocomplete))
73 
74     return bang_definition, new_autocomplete
75 
76 
77 def get_bang_url(search_query, external_bangs_db=None):
78     """
79     Redirects if the user supplied a correct bang search.
80     :param search_query: This is a search_query object which contains preferences and the submitted queries.
81     :return: None if the bang was invalid, else a string of the redirect url.
82     """
83     ret_val = None
84 
85     if external_bangs_db is None:
86         external_bangs_db = EXTERNAL_BANGS
87 
88     if search_query.external_bang:
89         bang_definition, _ = get_bang_definition_and_ac(external_bangs_db, search_query.external_bang)
90         if bang_definition and isinstance(bang_definition, str):
91             ret_val = resolve_bang_definition(bang_definition, search_query.query)[0]
92 
93     return ret_val
94
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/searx/external_bang.py b/searx/external_bang.py
--- a/searx/external_bang.py
+++ b/searx/external_bang.py
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: AGPL-3.0-or-later
 
-from urllib.parse import quote_plus
+from urllib.parse import quote_plus, urlparse
 from searx.data import EXTERNAL_BANGS
 
 LEAF_KEY = chr(16)
@@ -40,9 +40,15 @@
 
 def resolve_bang_definition(bang_definition, query):
     url, rank = bang_definition.split(chr(1))
-    url = url.replace(chr(2), quote_plus(query))
     if url.startswith('//'):
         url = 'https:' + url
+    if query:
+        url = url.replace(chr(2), quote_plus(query))
+    else:
+        # go to main instead of search page
+        o = urlparse(url)
+        url = o.scheme + '://' + o.netloc
+
     rank = int(rank) if len(rank) > 0 else 0
     return (url, rank)

{"golden_diff": "diff --git a/searx/external_bang.py b/searx/external_bang.py\n--- a/searx/external_bang.py\n+++ b/searx/external_bang.py\n@@ -1,6 +1,6 @@\n # SPDX-License-Identifier: AGPL-3.0-or-later\n \n-from urllib.parse import quote_plus\n+from urllib.parse import quote_plus, urlparse\n from searx.data import EXTERNAL_BANGS\n \n LEAF_KEY = chr(16)\n@@ -40,9 +40,15 @@\n \n def resolve_bang_definition(bang_definition, query):\n     url, rank = bang_definition.split(chr(1))\n-    url = url.replace(chr(2), quote_plus(query))\n     if url.startswith('//'):\n         url = 'https:' + url\n+    if query:\n+        url = url.replace(chr(2), quote_plus(query))\n+    else:\n+        # go to main instead of search page\n+        o = urlparse(url)\n+        url = o.scheme + '://' + o.netloc\n+\n     rank = int(rank) if len(rank) > 0 else 0\n     return (url, rank)\n", "issue": "Double bangs without query redirect to search URL instead of main page\n<!-- PLEASE FILL THESE FIELDS, IT REALLY HELPS THE MAINTAINERS OF SearXNG -->\r\n\r\n**Version of SearXNG, commit number if you are using on master branch and stipulate if you forked SearXNG**\r\n`2023.4.21+98387e29`\r\n\r\n**How did you install SearXNG?**\r\n`searxng-docker`\r\n\r\n**What happened?**\r\nDouble bangs without query redirect to search URL instead of main page\r\n\r\n**How To Reproduce**\r\nUse external bang without any search items e.g. `!!gh` and we land on `https://github.com/search?utf8=%E2%9C%93&q=` \r\n\r\n**Expected behavior**\r\n`!!gh` should redirect to `https://github.com` if no search items\n", "before_files": [{"content": "# SPDX-License-Identifier: AGPL-3.0-or-later\n\nfrom urllib.parse import quote_plus\nfrom searx.data import EXTERNAL_BANGS\n\nLEAF_KEY = chr(16)\n\n\ndef get_node(external_bangs_db, bang):\n    node = external_bangs_db['trie']\n    after = ''\n    before = ''\n    for bang_letter in bang:\n        after += bang_letter\n        if after in node and isinstance(node, dict):\n            node = node[after]\n            before += after\n            after = ''\n    return node, before, after\n\n\ndef get_bang_definition_and_ac(external_bangs_db, bang):\n    node, before, after = get_node(external_bangs_db, bang)\n\n    bang_definition = None\n    bang_ac_list = []\n    if after != '':\n        for k in node:\n            if k.startswith(after):\n                bang_ac_list.append(before + k)\n    elif isinstance(node, dict):\n        bang_definition = node.get(LEAF_KEY)\n        bang_ac_list = [before + k for k in node.keys() if k != LEAF_KEY]\n    elif isinstance(node, str):\n        bang_definition = node\n        bang_ac_list = []\n\n    return bang_definition, bang_ac_list\n\n\ndef resolve_bang_definition(bang_definition, query):\n    url, rank = bang_definition.split(chr(1))\n    url = url.replace(chr(2), quote_plus(query))\n    if url.startswith('//'):\n        url = 'https:' + url\n    rank = int(rank) if len(rank) > 0 else 0\n    return (url, rank)\n\n\ndef get_bang_definition_and_autocomplete(bang, external_bangs_db=None):\n    if external_bangs_db is None:\n        external_bangs_db = EXTERNAL_BANGS\n\n    bang_definition, bang_ac_list = get_bang_definition_and_ac(external_bangs_db, bang)\n\n    new_autocomplete = []\n    current = [*bang_ac_list]\n    done = set()\n    while len(current) > 0:\n        bang_ac = current.pop(0)\n        done.add(bang_ac)\n\n        current_bang_definition, current_bang_ac_list = get_bang_definition_and_ac(external_bangs_db, bang_ac)\n        if current_bang_definition:\n            _, order = resolve_bang_definition(current_bang_definition, '')\n            new_autocomplete.append((bang_ac, order))\n        for new_bang in current_bang_ac_list:\n            if new_bang not in done and new_bang not in current:\n                current.append(new_bang)\n\n    new_autocomplete.sort(key=lambda t: (-t[1], t[0]))\n    new_autocomplete = list(map(lambda t: t[0], new_autocomplete))\n\n    return bang_definition, new_autocomplete\n\n\ndef get_bang_url(search_query, external_bangs_db=None):\n    \"\"\"\n    Redirects if the user supplied a correct bang search.\n    :param search_query: This is a search_query object which contains preferences and the submitted queries.\n    :return: None if the bang was invalid, else a string of the redirect url.\n    \"\"\"\n    ret_val = None\n\n    if external_bangs_db is None:\n        external_bangs_db = EXTERNAL_BANGS\n\n    if search_query.external_bang:\n        bang_definition, _ = get_bang_definition_and_ac(external_bangs_db, search_query.external_bang)\n        if bang_definition and isinstance(bang_definition, str):\n            ret_val = resolve_bang_definition(bang_definition, search_query.query)[0]\n\n    return ret_val\n", "path": "searx/external_bang.py"}], "after_files": [{"content": "# SPDX-License-Identifier: AGPL-3.0-or-later\n\nfrom urllib.parse import quote_plus, urlparse\nfrom searx.data import EXTERNAL_BANGS\n\nLEAF_KEY = chr(16)\n\n\ndef get_node(external_bangs_db, bang):\n    node = external_bangs_db['trie']\n    after = ''\n    before = ''\n    for bang_letter in bang:\n        after += bang_letter\n        if after in node and isinstance(node, dict):\n            node = node[after]\n            before += after\n            after = ''\n    return node, before, after\n\n\ndef get_bang_definition_and_ac(external_bangs_db, bang):\n    node, before, after = get_node(external_bangs_db, bang)\n\n    bang_definition = None\n    bang_ac_list = []\n    if after != '':\n        for k in node:\n            if k.startswith(after):\n                bang_ac_list.append(before + k)\n    elif isinstance(node, dict):\n        bang_definition = node.get(LEAF_KEY)\n        bang_ac_list = [before + k for k in node.keys() if k != LEAF_KEY]\n    elif isinstance(node, str):\n        bang_definition = node\n        bang_ac_list = []\n\n    return bang_definition, bang_ac_list\n\n\ndef resolve_bang_definition(bang_definition, query):\n    url, rank = bang_definition.split(chr(1))\n    if url.startswith('//'):\n        url = 'https:' + url\n    if query:\n        url = url.replace(chr(2), quote_plus(query))\n    else:\n        # go to main instead of search page\n        o = urlparse(url)\n        url = o.scheme + '://' + o.netloc\n\n    rank = int(rank) if len(rank) > 0 else 0\n    return (url, rank)\n\n\ndef get_bang_definition_and_autocomplete(bang, external_bangs_db=None):\n    if external_bangs_db is None:\n        external_bangs_db = EXTERNAL_BANGS\n\n    bang_definition, bang_ac_list = get_bang_definition_and_ac(external_bangs_db, bang)\n\n    new_autocomplete = []\n    current = [*bang_ac_list]\n    done = set()\n    while len(current) > 0:\n        bang_ac = current.pop(0)\n        done.add(bang_ac)\n\n        current_bang_definition, current_bang_ac_list = get_bang_definition_and_ac(external_bangs_db, bang_ac)\n        if current_bang_definition:\n            _, order = resolve_bang_definition(current_bang_definition, '')\n            new_autocomplete.append((bang_ac, order))\n        for new_bang in current_bang_ac_list:\n            if new_bang not in done and new_bang not in current:\n                current.append(new_bang)\n\n    new_autocomplete.sort(key=lambda t: (-t[1], t[0]))\n    new_autocomplete = list(map(lambda t: t[0], new_autocomplete))\n\n    return bang_definition, new_autocomplete\n\n\ndef get_bang_url(search_query, external_bangs_db=None):\n    \"\"\"\n    Redirects if the user supplied a correct bang search.\n    :param search_query: This is a search_query object which contains preferences and the submitted queries.\n    :return: None if the bang was invalid, else a string of the redirect url.\n    \"\"\"\n    ret_val = None\n\n    if external_bangs_db is None:\n        external_bangs_db = EXTERNAL_BANGS\n\n    if search_query.external_bang:\n        bang_definition, _ = get_bang_definition_and_ac(external_bangs_db, search_query.external_bang)\n        if bang_definition and isinstance(bang_definition, str):\n            ret_val = resolve_bang_definition(bang_definition, search_query.query)[0]\n\n    return ret_val\n", "path": "searx/external_bang.py"}]}