diff --git a/qutebrowser/.config/qutebrowser/alias.py b/qutebrowser/.config/qutebrowser/alias.py index 5b0c865..f3e4279 100644 --- a/qutebrowser/.config/qutebrowser/alias.py +++ b/qutebrowser/.config/qutebrowser/alias.py @@ -1,4 +1,4 @@ -c.aliases["gem"] = "hint links userscript qute-gemini" +c.aliases["gem"] = "spawn --userscript qute-gemini " # Use q for quitting a tab (mimicks vim buffer) - qa is used for exiting c.aliases["q"] = "tab-close" diff --git a/qutebrowser/.config/qutebrowser/maps.py b/qutebrowser/.config/qutebrowser/maps.py index d691b49..0ba4a0e 100644 --- a/qutebrowser/.config/qutebrowser/maps.py +++ b/qutebrowser/.config/qutebrowser/maps.py @@ -6,6 +6,10 @@ lleader = "," ## CHANGED DEFAULTS +# the full power of qutebrowser at your fingertips for any gemini page! +config.bind("f", "hint links userscript qute-gemini") +config.bind("F", "hint links userscript qute-gemini-tab") + # rebind moving tabs to free for download config.bind("gG", "tab-give") # switch binds for scroll-marks and quick-/book-marks diff --git a/qutebrowser/.local/share/qutebrowser/userscripts/qute-gemini b/qutebrowser/.local/share/qutebrowser/userscripts/qute-gemini index 3e3110e..b9bd405 100755 --- a/qutebrowser/.local/share/qutebrowser/userscripts/qute-gemini +++ b/qutebrowser/.local/share/qutebrowser/userscripts/qute-gemini @@ -6,6 +6,20 @@ # SPDX-FileCopyrightText: 2020 petedussin # SPDX-FileCopyrightText: 2020-2021 Sotiris Papatheodorou # SPDX-License-Identifier: GPL-3.0-or-later +# 2022-2023 Marty Oehme (added stand-alone script capability) + +# Use it as a qutebrowser userscript to open gemini pages: +# Put this file in qutebrowser userscript folder and call command +# `:spawn --userscript qute-gemini "gemini://my-gemini-url.org"` +# or +# `:hint links userscript qute-gemini` to open from selected link +# Rename file to `qute-gemini-tab` (or create symlink) to open +# any gemini url as a new tab. + +# Since the script also opens normal URLs you can even replace your +# normal link hint mapping with it (usually f or F for tabbed) and +# continue surfing like normal, only that you can now also access +# any gemini pages as if they were part of the normal http protocol. import cgi import html @@ -41,7 +55,8 @@ CSS _status_code_desc = { "1": "Gemini status code 1 Input. This is not implemented in qute-gemini.", "10": "Gemini status code 10 Input. This is not implemented in qute-gemini.", - "11": "Gemini status code 11 Sensitive Input. This is not implemented in qute-gemini.", + "11": """Gemini status code 11 Sensitive Input. This is not implemented + in qute-gemini.""", "3": "Gemini status code 3 Redirect. Stopped after " + str(_max_redirects) + " redirects.", @@ -53,28 +68,41 @@ _status_code_desc = { + " redirects.", "4": "Gemini status code 4 Temporary Failure. Server message: META", "40": "Gemini status code 40 Temporary Failure. Server message: META", - "41": "Gemini status code 41 Server Unavailable. The server is unavailable due to overload or maintenance. Server message: META", - "42": "Gemini status code 42 CGI Error. A CGI process, or similar system for generating dynamic content, died unexpectedly or timed out. Server message: META", - "43": "Gemini status code 43 Proxy Error. A proxy request failed because the server was unable to successfully complete a transaction with the remote host. Server message: META", - "44": "Gemini status code 44 Slow Down. Rate limiting is in effect. Please wait META seconds before making another request to this server.", + "41": """Gemini status code 41 Server Unavailable. + The server is unavailable due to overload or maintenance. Server message: META""", + "42": """Gemini status code 42 CGI Error. + A CGI process, or similar system for generating dynamic content, + died unexpectedly or timed out. Server message: META""", + "43": """Gemini status code 43 Proxy Error. + A proxy request failed because the server was unable to successfully + complete a transaction with the remote host. Server message: META""", + "44": """Gemini status code 44 Slow Down. Rate limiting is in effect. + Please wait META seconds before making another request to this server.""", "5": "Gemini status code 5 Permanent Failure. Server message: META", "50": "Gemini status code 50 Permanent Failure. Server message: META", - "51": "Gemini status code 51 Not Found. he requested resource could not be found but may be available in the future. Server message: META", - "52": "Gemini status code 52 Gone. The resource requested is no longer available and will not be available again. Server message: META", - "53": "Gemini status code 53 Proxy Request Refused. The request was for a resource at a domain not served by the server and the server does not accept proxy requests. Server message: META", - "59": "Gemini status code 59 Bad Request. The server was unable to parse the client's request, presumably due to a malformed request. Server message: META", - "6": "Gemini status code 6 Client Certificate Required. This is not implemented in qute-gemini.", + "51": """Gemini status code 51 Not Found. The requested resource could + not be found but may be available in the future. Server message: META""", + "52": """Gemini status code 52 Gone. The resource requested is no longer + available and will not be available again. Server message: META""", + "53": """Gemini status code 53 Proxy Request Refused. The request was for + a resource at a domain not served by the server and the server does + not accept proxy requests. Server message: META""", + "59": """Gemini status code 59 Bad Request. The server was unable to + parse the client's request, presumably due to a malformed request. + Server message: META""", + "6": """Gemini status code 6 Client Certificate Required. + This is not implemented in qute-gemini.""", } def qute_url() -> str: """Get the URL passed to the script by qutebrowser.""" - return os.environ["QUTE_URL"] + return os.environ.get("QUTE_URL", "") def qute_fifo() -> str: """Get the FIFO or file to write qutebrowser commands to.""" - return os.environ["QUTE_FIFO"] + return os.environ.get("QUTE_FIFO", "") def html_href(url: str, description: str) -> str: @@ -118,7 +146,7 @@ def gemini_fetch_url(url: str) -> Tuple[str, str, str, str, str]: url = "gemini://" + url parsed_url = urllib.parse.urlparse(url) if parsed_url.scheme != "gemini": - return "", "Received non-gemini:// URL: " + url + return "", "Received non-gemini:// URL: " + url, "59", "", "Non-gemini URL" if parsed_url.port is not None: useport = parsed_url.port else: @@ -214,15 +242,15 @@ def gemtext_to_html( pass # Link elif line.startswith("=>"): - l = line[2:].split(None, 1) + ln = line[2:].split(None, 1) # Use the URL itself as the description if there is none - if len(l) == 1: - l.append(l[0]) + if len(ln) == 1: + ln.append(ln[0]) # Encode the link description - l[1] = html.escape(l[1]) + ln[1] = html.escape(ln[1]) # Resolve relative URLs - l[0] = gemini_absolutise_url(url, l[0]) - lines.append("\t\t

" + html_href(l[0], l[1]) + "

") + ln[0] = gemini_absolutise_url(url, ln[0]) + lines.append("\t\t

" + html_href(ln[0], ln[1]) + "

") # Preformated toggle elif line.startswith("```"): if in_pre: @@ -316,7 +344,7 @@ def qute_error_page(url: str, description: str) -> str: return "data:text/html;charset=UTF-8," + urllib.parse.quote(html_page) -def open_gemini(url: str, open_args: str) -> None: +def open_gemini(url: str) -> str: """Open Gemini URL in qutebrowser.""" # Get the Gemini content content, content_url, status, meta, error_msg = gemini_fetch_url(url) @@ -328,18 +356,30 @@ def open_gemini(url: str, open_args: str) -> None: tmpf = tempfile.NamedTemporaryFile("w", suffix=".html", delete=False) tmp_filename = tmpf.name tmpf.close() + if not tmp_filename: + return "" with open(tmp_filename, "w") as f: f.write(gemtext_to_html(content, content_url, url, status, meta)) open_url = " file://" + tmp_filename # Open the HTML file in qutebrowser - with open(qute_fifo(), "w") as qfifo: - qfifo.write("open " + open_args + open_url) + return open_url -def open_other(url: str, open_args: str) -> None: - """Open non-Gemini URL in qutebrowser.""" - with open(qute_fifo(), "w") as qfifo: - qfifo.write("open " + open_args + " " + url) +def open_url(url: str, open_args: str) -> None: + parsed_url = urllib.parse.urlparse(url) + if parsed_url.scheme == "gemini": + to_open = open_gemini(url) + else: + to_open = url + if not to_open: + return + + fifo = qute_fifo() + if fifo and fifo != "": + with open(fifo, "w") as qfifo: + qfifo.write(f"open {open_args} {to_open}") + return + os.system(f"xdg-open {to_open}") if __name__ == "__main__": @@ -348,10 +388,11 @@ if __name__ == "__main__": open_args = "-t" else: open_args = "" - # Select how to open the URL depending on its scheme - url = qute_url() - parsed_url = urllib.parse.urlparse(url) - if parsed_url.scheme == "gemini": - open_gemini(url, open_args) + + # Take url to open as argument or from qutebrowser url + if len(sys.argv) > 1: + url = sys.argv[1] else: - open_other(url, open_args) + url = qute_url() + # Select how to open the URL depending on its scheme + open_url(url, open_args)